diff options
| author | Havoc Pennington <hp@redhat.com> | 2005-01-17 03:53:40 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2005-01-17 03:53:40 +0000 | 
| commit | 7bf62e31a3c820852271768fafc04ba95c31a19f (patch) | |
| tree | 660d6e210d04143773da2e86d3b3e8dae8be5cc0 | |
| parent | 4c1a2a760b67b4600db3e5b9c2ad0056b5cf32b6 (diff) | |
2005-01-16  Havoc Pennington  <hp@redhat.com>
        This is about it on what can be disabled/deleted from libdbus
	easily, back below 150K anyhow. Deeper cuts are more work than
	just turning the code off as I've done here.
	* dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the
	signed int convenience funcs
	* dbus/dbus-internals.c (_dbus_verbose_real): omit when not in
	verbose mode
	* dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking
	things out of libdbus
	* dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same
	* dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it
	tests-enabled-only, though it should probably be deleted)
	* dbus/dbus-message-util.c: same stuff
	* dbus/dbus-auth-util.c: same stuff
| -rw-r--r-- | ChangeLog | 24 | ||||
| -rw-r--r-- | dbus/Makefile.am | 11 | ||||
| -rw-r--r-- | dbus/dbus-auth-util.c | 169 | ||||
| -rw-r--r-- | dbus/dbus-auth.c | 137 | ||||
| -rw-r--r-- | dbus/dbus-hash.c | 25 | ||||
| -rw-r--r-- | dbus/dbus-internals.c | 6 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 8 | ||||
| -rw-r--r-- | dbus/dbus-list.c | 10 | ||||
| -rw-r--r-- | dbus/dbus-marshal-basic.c | 29 | ||||
| -rw-r--r-- | dbus/dbus-marshal-basic.h | 5 | ||||
| -rw-r--r-- | dbus/dbus-marshal-recursive-util.c | 2963 | ||||
| -rw-r--r-- | dbus/dbus-marshal-recursive.c | 2923 | ||||
| -rw-r--r-- | dbus/dbus-message-builder.c | 109 | ||||
| -rw-r--r-- | dbus/dbus-message-internal.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-message-private.h | 119 | ||||
| -rw-r--r-- | dbus/dbus-message-util.c | 1309 | ||||
| -rw-r--r-- | dbus/dbus-message.c | 1382 | ||||
| -rw-r--r-- | dbus/dbus-string-private.h | 56 | ||||
| -rw-r--r-- | dbus/dbus-string-util.c | 727 | ||||
| -rw-r--r-- | dbus/dbus-string.c | 871 | ||||
| -rw-r--r-- | dbus/dbus-string.h | 8 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-util.c | 871 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 374 | ||||
| -rw-r--r-- | dbus/dbus-userdb-util.c | 1 | ||||
| -rw-r--r-- | dbus/dbus-userdb.c | 2 | ||||
| -rwxr-xr-x | test/unused-code-gc.py | 2 | 
26 files changed, 6517 insertions, 5626 deletions
| @@ -1,5 +1,29 @@  2005-01-16  Havoc Pennington  <hp@redhat.com> +        This is about it on what can be disabled/deleted from libdbus +	easily, back below 150K anyhow. Deeper cuts are more work than  +	just turning the code off as I've done here. +	 +	* dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the +	signed int convenience funcs + +	* dbus/dbus-internals.c (_dbus_verbose_real): omit when not in +	verbose mode + +	* dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking +	things out of libdbus + +	* dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same +	 +	* dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it +	tests-enabled-only, though it should probably be deleted) + +	* dbus/dbus-message-util.c: same stuff + +	* dbus/dbus-auth-util.c: same stuff + +2005-01-16  Havoc Pennington  <hp@redhat.com> +  	* dbus/dbus-userdb-util.c: split out part of dbus-userdb.c  	* dbus/dbus-sysdeps.c (_dbus_uid_from_string): move here to pave diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 429c9ad9..216b168d 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -62,15 +62,16 @@ DBUS_LIB_SOURCES=				\  	dbus-marshal-validate.h			\  	dbus-message.c				\  	dbus-message-internal.h			\ +	dbus-message-private.h			\  	dbus-object-tree.c			\  	dbus-object-tree.h			\  	dbus-pending-call.c			\  	dbus-resources.c			\  	dbus-resources.h			\  	dbus-server.c				\ -	dbus-server-protected.h			\  	dbus-server-debug-pipe.c		\  	dbus-server-debug-pipe.h		\ +	dbus-server-protected.h			\  	dbus-server-unix.c			\  	dbus-server-unix.h			\  	dbus-sha.c				\ @@ -121,16 +122,18 @@ DBUS_SHARED_SOURCES=				\  ### should be underscore-prefixed but don't really need   ### to be unless they move to DBUS_SHARED_SOURCES later)  DBUS_UTIL_SOURCES=				\ +	dbus-auth-util.c			\  	dbus-mainloop.c				\  	dbus-mainloop.h				\ +	dbus-marshal-recursive-util.c		\ +	dbus-message-util.c			\  	dbus-spawn.c				\  	dbus-spawn.h				\ +	dbus-string-util.c			\  	dbus-sysdeps-util.c			\ -	dbus-sysdeps-util.h			\  	dbus-test.c				\  	dbus-test.h				\ -	dbus-userdb-util.c			\ -	dbus-userdb-util.h +	dbus-userdb-util.c  libdbus_1_la_SOURCES=				\  	$(DBUS_LIB_SOURCES)			\ diff --git a/dbus/dbus-auth-util.c b/dbus/dbus-auth-util.c new file mode 100644 index 00000000..4d25cf0a --- /dev/null +++ b/dbus/dbus-auth-util.c @@ -0,0 +1,169 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-auth-util.c Would be in dbus-auth.c, but only used for tests/bus + * + * Copyright (C) 2002, 2003, 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-internals.h" +#include "dbus-test.h" +#include "dbus-auth.h" + +/** + * @addtogroup DBusAuth + * @{ + */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include "dbus-auth-script.h" +#include <stdio.h> + +static dbus_bool_t +process_test_subdir (const DBusString          *test_base_dir, +                     const char                *subdir) +{ +  DBusString test_directory; +  DBusString filename; +  DBusDirIter *dir; +  dbus_bool_t retval; +  DBusError error; + +  retval = FALSE; +  dir = NULL; +   +  if (!_dbus_string_init (&test_directory)) +    _dbus_assert_not_reached ("didn't allocate test_directory\n"); + +  _dbus_string_init_const (&filename, subdir); +   +  if (!_dbus_string_copy (test_base_dir, 0, +                          &test_directory, 0)) +    _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); +   +  if (!_dbus_concat_dir_and_file (&test_directory, &filename))     +    _dbus_assert_not_reached ("couldn't allocate full path"); + +  _dbus_string_free (&filename); +  if (!_dbus_string_init (&filename)) +    _dbus_assert_not_reached ("didn't allocate filename string\n"); + +  dbus_error_init (&error); +  dir = _dbus_directory_open (&test_directory, &error); +  if (dir == NULL) +    { +      _dbus_warn ("Could not open %s: %s\n", +                  _dbus_string_get_const_data (&test_directory), +                  error.message); +      dbus_error_free (&error); +      goto failed; +    } + +  printf ("Testing %s:\n", subdir); +   + next: +  while (_dbus_directory_get_next_file (dir, &filename, &error)) +    { +      DBusString full_path; +       +      if (!_dbus_string_init (&full_path)) +        _dbus_assert_not_reached ("couldn't init string"); + +      if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) +        _dbus_assert_not_reached ("couldn't copy dir to full_path"); + +      if (!_dbus_concat_dir_and_file (&full_path, &filename)) +        _dbus_assert_not_reached ("couldn't concat file to dir"); + +      if (!_dbus_string_ends_with_c_str (&filename, ".auth-script")) +        { +          _dbus_verbose ("Skipping non-.auth-script file %s\n", +                         _dbus_string_get_const_data (&filename)); +	  _dbus_string_free (&full_path); +          goto next; +        } + +      printf ("    %s\n", _dbus_string_get_const_data (&filename)); +       +      if (!_dbus_auth_script_run (&full_path)) +        { +          _dbus_string_free (&full_path); +          goto failed; +        } +      else +        _dbus_string_free (&full_path); +    } + +  if (dbus_error_is_set (&error)) +    { +      _dbus_warn ("Could not get next file in %s: %s\n", +                  _dbus_string_get_const_data (&test_directory), error.message); +      dbus_error_free (&error); +      goto failed; +    } +     +  retval = TRUE; +   + failed: + +  if (dir) +    _dbus_directory_close (dir); +  _dbus_string_free (&test_directory); +  _dbus_string_free (&filename); + +  return retval; +} + +static dbus_bool_t +process_test_dirs (const char *test_data_dir) +{ +  DBusString test_directory; +  dbus_bool_t retval; + +  retval = FALSE; +   +  _dbus_string_init_const (&test_directory, test_data_dir); + +  if (!process_test_subdir (&test_directory, "auth")) +    goto failed; + +  retval = TRUE; +   + failed: + +  _dbus_string_free (&test_directory); +   +  return retval; +} + +dbus_bool_t +_dbus_auth_test (const char *test_data_dir) +{ +   +  if (test_data_dir == NULL) +    return TRUE; +   +  if (!process_test_dirs (test_data_dir)) +    return FALSE; + +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index b0793e06..eb8d5742 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -2392,139 +2392,4 @@ _dbus_auth_set_context (DBusAuth               *auth,  /** @} */ -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include "dbus-auth-script.h" -#include <stdio.h> - -static dbus_bool_t -process_test_subdir (const DBusString          *test_base_dir, -                     const char                *subdir) -{ -  DBusString test_directory; -  DBusString filename; -  DBusDirIter *dir; -  dbus_bool_t retval; -  DBusError error; - -  retval = FALSE; -  dir = NULL; -   -  if (!_dbus_string_init (&test_directory)) -    _dbus_assert_not_reached ("didn't allocate test_directory\n"); - -  _dbus_string_init_const (&filename, subdir); -   -  if (!_dbus_string_copy (test_base_dir, 0, -                          &test_directory, 0)) -    _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); -   -  if (!_dbus_concat_dir_and_file (&test_directory, &filename))     -    _dbus_assert_not_reached ("couldn't allocate full path"); - -  _dbus_string_free (&filename); -  if (!_dbus_string_init (&filename)) -    _dbus_assert_not_reached ("didn't allocate filename string\n"); - -  dbus_error_init (&error); -  dir = _dbus_directory_open (&test_directory, &error); -  if (dir == NULL) -    { -      _dbus_warn ("Could not open %s: %s\n", -                  _dbus_string_get_const_data (&test_directory), -                  error.message); -      dbus_error_free (&error); -      goto failed; -    } - -  printf ("Testing %s:\n", subdir); -   - next: -  while (_dbus_directory_get_next_file (dir, &filename, &error)) -    { -      DBusString full_path; -       -      if (!_dbus_string_init (&full_path)) -        _dbus_assert_not_reached ("couldn't init string"); - -      if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) -        _dbus_assert_not_reached ("couldn't copy dir to full_path"); - -      if (!_dbus_concat_dir_and_file (&full_path, &filename)) -        _dbus_assert_not_reached ("couldn't concat file to dir"); - -      if (!_dbus_string_ends_with_c_str (&filename, ".auth-script")) -        { -          _dbus_verbose ("Skipping non-.auth-script file %s\n", -                         _dbus_string_get_const_data (&filename)); -	  _dbus_string_free (&full_path); -          goto next; -        } - -      printf ("    %s\n", _dbus_string_get_const_data (&filename)); -       -      if (!_dbus_auth_script_run (&full_path)) -        { -          _dbus_string_free (&full_path); -          goto failed; -        } -      else -        _dbus_string_free (&full_path); -    } - -  if (dbus_error_is_set (&error)) -    { -      _dbus_warn ("Could not get next file in %s: %s\n", -                  _dbus_string_get_const_data (&test_directory), error.message); -      dbus_error_free (&error); -      goto failed; -    } -     -  retval = TRUE; -   - failed: - -  if (dir) -    _dbus_directory_close (dir); -  _dbus_string_free (&test_directory); -  _dbus_string_free (&filename); - -  return retval; -} - -static dbus_bool_t -process_test_dirs (const char *test_data_dir) -{ -  DBusString test_directory; -  dbus_bool_t retval; - -  retval = FALSE; -   -  _dbus_string_init_const (&test_directory, test_data_dir); - -  if (!process_test_subdir (&test_directory, "auth")) -    goto failed; - -  retval = TRUE; -   - failed: - -  _dbus_string_free (&test_directory); -   -  return retval; -} - -dbus_bool_t -_dbus_auth_test (const char *test_data_dir) -{ -   -  if (test_data_dir == NULL) -    return TRUE; -   -  if (!process_test_dirs (test_data_dir)) -    return FALSE; - -  return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ +/* tests in dbus-auth-util.c */ diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index c2ebb0f0..fa2104b3 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -231,13 +231,17 @@ static DBusHashEntry* find_string_function      (DBusHashTable          *table,                                                   dbus_bool_t             create_if_not_found,                                                   DBusHashEntry        ***bucket,                                                   DBusPreallocatedHash   *preallocated); +#ifdef DBUS_BUILD_TESTS  static DBusHashEntry* find_two_strings_function (DBusHashTable          *table,                                                   void                   *key,                                                   dbus_bool_t             create_if_not_found,                                                   DBusHashEntry        ***bucket,                                                   DBusPreallocatedHash   *preallocated); +#endif  static unsigned int   string_hash               (const char             *str); +#ifdef DBUS_BUILD_TESTS  static unsigned int   two_strings_hash          (const char             *str); +#endif  static void           rebuild_table             (DBusHashTable          *table);  static DBusHashEntry* alloc_entry               (DBusHashTable          *table);  static void           remove_entry              (DBusHashTable          *table, @@ -330,7 +334,9 @@ _dbus_hash_table_new (DBusHashType     type,        table->find_function = find_string_function;        break;      case DBUS_HASH_TWO_STRINGS: +#ifdef DBUS_BUILD_TESTS        table->find_function = find_two_strings_function; +#endif        break;      default:        _dbus_assert_not_reached ("Unknown hash table type"); @@ -696,6 +702,7 @@ _dbus_hash_iter_get_string_key (DBusHashIter *iter)    return real->entry->key;  } +#ifdef DBUS_BUILD_TESTS  /**   * Gets the key for the current entry.   * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS @@ -713,6 +720,7 @@ _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)    return real->entry->key;  } +#endif /* DBUS_BUILD_TESTS */  /**   * A low-level but efficient interface for manipulating the hash @@ -849,6 +857,7 @@ string_hash (const char *str)    return h;  } +#ifdef DBUS_BUILD_TESTS  /* This hashes a memory block with two nul-terminated strings   * in it, used in dbus-object-registry.c at the moment.   */ @@ -867,6 +876,7 @@ two_strings_hash (const char *str)    return h;  } +#endif /* DBUS_BUILD_TESTS */  /** Key comparison function */  typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); @@ -928,6 +938,7 @@ find_string_function (DBusHashTable        *table,                                  preallocated);  } +#ifdef DBUS_BUILD_TESTS  static int  two_strings_cmp (const char *a,                   const char *b) @@ -945,7 +956,9 @@ two_strings_cmp (const char *a,    return strcmp (a + len_a + 1, b + len_b + 1);  } +#endif +#ifdef DBUS_BUILD_TESTS  static DBusHashEntry*  find_two_strings_function (DBusHashTable        *table,                             void                 *key, @@ -961,6 +974,7 @@ find_two_strings_function (DBusHashTable        *table,                                  (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,                                  preallocated);  } +#endif /* DBUS_BUILD_TESTS */  static DBusHashEntry*  find_direct_function (DBusHashTable        *table, @@ -1077,7 +1091,12 @@ rebuild_table (DBusHashTable *table)                idx = string_hash (entry->key) & table->mask;                break;              case DBUS_HASH_TWO_STRINGS: +#ifdef DBUS_BUILD_TESTS                idx = two_strings_hash (entry->key) & table->mask; +#else +              idx = 0; +              _dbus_assert_not_reached ("two-strings is not enabled"); +#endif                break;              case DBUS_HASH_INT:              case DBUS_HASH_ULONG: @@ -1127,6 +1146,7 @@ _dbus_hash_table_lookup_string (DBusHashTable *table,      return NULL;  } +#ifdef DBUS_BUILD_TESTS  /**   * Looks up the value for a given string in a hash table   * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value @@ -1151,6 +1171,7 @@ _dbus_hash_table_lookup_two_strings (DBusHashTable *table,    else      return NULL;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Looks up the value for a given integer in a hash table @@ -1258,6 +1279,7 @@ _dbus_hash_table_remove_string (DBusHashTable *table,      return FALSE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Removes the hash entry for the given key. If no hash entry   * for the key exists, does nothing. @@ -1285,6 +1307,7 @@ _dbus_hash_table_remove_two_strings (DBusHashTable *table,    else      return FALSE;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Removes the hash entry for the given key. If no hash entry @@ -1407,6 +1430,7 @@ _dbus_hash_table_insert_string (DBusHashTable *table,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Creates a hash entry with the given key and value.   * The key and value are not copied; they are stored @@ -1447,6 +1471,7 @@ _dbus_hash_table_insert_two_strings (DBusHashTable *table,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Creates a hash entry with the given key and value. diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index eba3174d..8d0a968b 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -174,6 +174,8 @@ _dbus_warn (const char *format,    va_end (args);  } +#ifdef DBUS_ENABLE_VERBOSE_MODE +  static dbus_bool_t verbose_initted = FALSE;  /** @@ -238,6 +240,8 @@ _dbus_verbose_reset_real (void)    verbose_initted = FALSE;  } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ +  /**   * Duplicates a string. Result must be freed with   * dbus_free(). Returns #NULL if memory allocation fails. @@ -354,6 +358,7 @@ _dbus_string_array_contains (const char **array,    return FALSE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Returns a string describing the given name.   * @@ -387,6 +392,7 @@ _dbus_header_field_to_string (int header_field)        return "unknown";      }  } +#endif /* DBUS_BUILD_TESTS */  #ifndef DBUS_DISABLE_CHECKS  /** String used in _dbus_return_if_fail macro */ diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 5d6f31f2..2ffd2341 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -39,9 +39,6 @@ DBUS_BEGIN_DECLS  void _dbus_warn               (const char *format,                                 ...) _DBUS_GNUC_PRINTF (1, 2); -void _dbus_verbose_real       (const char *format, -                               ...) _DBUS_GNUC_PRINTF (1, 2); -void _dbus_verbose_reset_real (void);  #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)  #define _DBUS_FUNCTION_NAME __func__ @@ -79,6 +76,11 @@ void _dbus_verbose_reset_real (void);  #endif  #ifdef DBUS_ENABLE_VERBOSE_MODE + +void _dbus_verbose_real       (const char *format, +                               ...) _DBUS_GNUC_PRINTF (1, 2); +void _dbus_verbose_reset_real (void); +  #  define _dbus_verbose _dbus_verbose_real  #  define _dbus_verbose_reset _dbus_verbose_reset_real  #else diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c index 00b03d41..949e70a8 100644 --- a/dbus/dbus-list.c +++ b/dbus/dbus-list.c @@ -126,6 +126,7 @@ link_before (DBusList **list,      }  } +#ifdef DBUS_BUILD_TESTS  static void  link_after (DBusList **list,              DBusList  *after_this_link, @@ -145,6 +146,7 @@ link_after (DBusList **list,        link->next->prev = link;      }  } +#endif /* DBUS_BUILD_TESTS */  /** @} */ @@ -313,6 +315,7 @@ _dbus_list_prepend_link (DBusList **list,    link_before (list, *list, link);  } +#ifdef DBUS_BUILD_TESTS  /**   * Inserts data into the list before the given existing link.   *  @@ -341,7 +344,9 @@ _dbus_list_insert_before (DBusList **list,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */ +#ifdef DBUS_BUILD_TESTS  /**   * Inserts data into the list after the given existing link.   *  @@ -370,6 +375,7 @@ _dbus_list_insert_after (DBusList **list,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Inserts a link into the list before the given existing link. @@ -389,6 +395,7 @@ _dbus_list_insert_before_link (DBusList **list,      link_before (list, before_this_link, link);  } +#ifdef DBUS_BUILD_TESTS  /**   * Inserts a link into the list after the given existing link.   *  @@ -406,6 +413,7 @@ _dbus_list_insert_after_link (DBusList **list,    else        link_after (list, after_this_link, link);  } +#endif /* DBUS_BUILD_TESTS */  /**   * Removes a value from the list. Only removes the @@ -690,6 +698,7 @@ _dbus_list_pop_last (DBusList **list)    return data;  } +#ifdef DBUS_BUILD_TESTS  /**   * Removes the last link in the list and returns it.  This is a   * constant-time operation. @@ -710,6 +719,7 @@ _dbus_list_pop_last_link (DBusList **list)    return link;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Copies a list. This is a linear-time operation.  If there isn't diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index df154b54..94161af0 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -88,21 +88,6 @@ _dbus_pack_uint32 (dbus_uint32_t   value,    pack_4_octets (value, byte_order, data);  } -/** - * Packs a 32 bit signed integer into a data pointer. - * - * @param value the value - * @param byte_order the byte order to use - * @param data the data pointer - */ -void -_dbus_pack_int32 (dbus_int32_t   value, -                  int            byte_order, -                  unsigned char *data) -{ -  pack_4_octets ((dbus_uint32_t) value, byte_order, data); -} -  #ifndef DBUS_HAVE_INT64  /* from ORBit */  static void @@ -183,20 +168,6 @@ _dbus_unpack_uint32 (int                  byte_order,  }  #endif /* _dbus_unpack_uint32 */ -/** - * Unpacks a 32 bit signed integer from a data pointer - * - * @param byte_order The byte order to use - * @param data the data pointer - * @returns the integer - */ -dbus_int32_t -_dbus_unpack_int32 (int                  byte_order, -                    const unsigned char *data) -{ -  return (dbus_int32_t) _dbus_unpack_uint32 (byte_order, data); -} -  static void  set_4_octets (DBusString          *str,                int                  offset, diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h index 870fc0f7..f416689c 100644 --- a/dbus/dbus-marshal-basic.h +++ b/dbus/dbus-marshal-basic.h @@ -152,11 +152,6 @@ typedef union       DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)(data)))  #endif -void          _dbus_pack_int32    (dbus_int32_t         value, -                                   int                  byte_order, -                                   unsigned char       *data); -dbus_int32_t  _dbus_unpack_int32  (int                  byte_order, -                                   const unsigned char *data);  void          _dbus_pack_uint32   (dbus_uint32_t        value,                                     int                  byte_order,                                     unsigned char       *data); diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c new file mode 100644 index 00000000..cd80ea07 --- /dev/null +++ b/dbus/dbus-marshal-recursive-util.c @@ -0,0 +1,2963 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-marshal-recursive-util.c  Would be in dbus-marshal-recursive.c, but only used in bus/tests + * + * Copyright (C) 2004, 2005 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-marshal-basic.h" +#include "dbus-internals.h" + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include "dbus-list.h" +#include <stdio.h> +#include <stdlib.h> + +static int +first_type_in_signature (const DBusString *str, +                         int               pos) +{ +  unsigned char t; + +  t = _dbus_string_get_byte (str, pos); + +  if (t == DBUS_STRUCT_BEGIN_CHAR) +    return DBUS_TYPE_STRUCT; +  else +    return t; +} + +/* Whether to do the OOM stuff (only with other expensive tests) */ +#define TEST_OOM_HANDLING 0 +/* We do start offset 0 through 9, to get various alignment cases. Still this + * obviously makes the test suite run 10x as slow. + */ +#define MAX_INITIAL_OFFSET 9 + +/* Largest iteration count to test copying, realignment, + * etc. with. i.e. we only test this stuff with some of the smaller + * data sets. + */ +#define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000 + +typedef struct +{ +  int byte_order; +  int initial_offset; +  DBusString signature; +  DBusString body; +} DataBlock; + +typedef struct +{ +  int saved_sig_len; +  int saved_body_len; +} DataBlockState; + +#define N_FENCE_BYTES 5 +#define FENCE_BYTES_STR "abcde" +#define INITIAL_PADDING_BYTE '\0' + +static dbus_bool_t +data_block_init (DataBlock *block, +                 int        byte_order, +                 int        initial_offset) +{ +  if (!_dbus_string_init (&block->signature)) +    return FALSE; + +  if (!_dbus_string_init (&block->body)) +    { +      _dbus_string_free (&block->signature); +      return FALSE; +    } + +  if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset, +                                  INITIAL_PADDING_BYTE) || +      !_dbus_string_insert_bytes (&block->body, 0, initial_offset, +                                  INITIAL_PADDING_BYTE) || +      !_dbus_string_append (&block->signature, FENCE_BYTES_STR) || +      !_dbus_string_append (&block->body, FENCE_BYTES_STR)) +    { +      _dbus_string_free (&block->signature); +      _dbus_string_free (&block->body); +      return FALSE; +    } + +  block->byte_order = byte_order; +  block->initial_offset = initial_offset; + +  return TRUE; +} + +static void +data_block_save (DataBlock      *block, +                 DataBlockState *state) +{ +  state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES; +  state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES; +} + +static void +data_block_restore (DataBlock      *block, +                    DataBlockState *state) +{ +  _dbus_string_delete (&block->signature, +                       state->saved_sig_len, +                       _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES); +  _dbus_string_delete (&block->body, +                       state->saved_body_len, +                       _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES); +} + +static void +data_block_verify (DataBlock *block) +{ +  if (!_dbus_string_ends_with_c_str (&block->signature, +                                     FENCE_BYTES_STR)) +    { +      int offset; + +      offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8; +      if (offset < 0) +        offset = 0; + +      _dbus_verbose_bytes_of_string (&block->signature, +                                     offset, +                                     _dbus_string_get_length (&block->signature) - offset); +      _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature"); +    } +  if (!_dbus_string_ends_with_c_str (&block->body, +                                     FENCE_BYTES_STR)) +    { +      int offset; + +      offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8; +      if (offset < 0) +        offset = 0; + +      _dbus_verbose_bytes_of_string (&block->body, +                                     offset, +                                     _dbus_string_get_length (&block->body) - offset); +      _dbus_assert_not_reached ("block did not verify: bad bytes at end of body"); +    } + +  _dbus_assert (_dbus_string_validate_nul (&block->signature, +                                           0, block->initial_offset)); +  _dbus_assert (_dbus_string_validate_nul (&block->body, +                                           0, block->initial_offset)); +} + +static void +data_block_free (DataBlock *block) +{ +  data_block_verify (block); + +  _dbus_string_free (&block->signature); +  _dbus_string_free (&block->body); +} + +static void +data_block_reset (DataBlock *block) +{ +  data_block_verify (block); + +  _dbus_string_delete (&block->signature, +                       block->initial_offset, +                       _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset); +  _dbus_string_delete (&block->body, +                       block->initial_offset, +                       _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset); + +  data_block_verify (block); +} + +static void +data_block_init_reader_writer (DataBlock      *block, +                               DBusTypeReader *reader, +                               DBusTypeWriter *writer) +{ +  if (reader) +    _dbus_type_reader_init (reader, +                            block->byte_order, +                            &block->signature, +                            block->initial_offset, +                            &block->body, +                            block->initial_offset); + +  if (writer) +    _dbus_type_writer_init (writer, +                            block->byte_order, +                            &block->signature, +                            _dbus_string_get_length (&block->signature) - N_FENCE_BYTES, +                            &block->body, +                            _dbus_string_get_length (&block->body) - N_FENCE_BYTES); +} + +static void +real_check_expected_type (DBusTypeReader *reader, +                          int             expected, +                          const char     *funcname, +                          int             line) +{ +  int t; + +  t = _dbus_type_reader_get_current_type (reader); + +  if (t != expected) +    { +      _dbus_warn ("Read type %s while expecting %s at %s line %d\n", +                  _dbus_type_to_string (t), +                  _dbus_type_to_string (expected), +                  funcname, line); + +      _dbus_assert_not_reached ("read wrong type"); +    } +} + +#define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__) + +#define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \ + {                                                                                      \ +    _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \ +                              _DBUS_FUNCTION_NAME, __LINE__);                           \ +    _dbus_assert_not_reached ("test failed");                                           \ + }                                                                                      \ +} while (0) + +#define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \ + {                                                                                      \ +    _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \ +                              _DBUS_FUNCTION_NAME, __LINE__);                           \ +    _dbus_assert_not_reached ("test failed");                                           \ + }                                                                                      \ + check_expected_type (reader, DBUS_TYPE_INVALID);                                       \ +} while (0) + +typedef struct TestTypeNode               TestTypeNode; +typedef struct TestTypeNodeClass          TestTypeNodeClass; +typedef struct TestTypeNodeContainer      TestTypeNodeContainer; +typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass; + +struct TestTypeNode +{ +  const TestTypeNodeClass *klass; +}; + +struct TestTypeNodeContainer +{ +  TestTypeNode base; +  DBusList    *children; +}; + +struct TestTypeNodeClass +{ +  int typecode; + +  int instance_size; + +  int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */ + +  dbus_bool_t   (* construct)     (TestTypeNode   *node); +  void          (* destroy)       (TestTypeNode   *node); + +  dbus_bool_t (* write_value)     (TestTypeNode   *node, +                                   DataBlock      *block, +                                   DBusTypeWriter *writer, +                                   int             seed); +  dbus_bool_t (* read_value)      (TestTypeNode   *node, +                                   DBusTypeReader *reader, +                                   int             seed); +  dbus_bool_t (* set_value)       (TestTypeNode   *node, +                                   DBusTypeReader *reader, +                                   DBusTypeReader *realign_root, +                                   int             seed); +  dbus_bool_t (* build_signature) (TestTypeNode   *node, +                                   DBusString     *str); +  dbus_bool_t (* write_multi)     (TestTypeNode   *node, +                                   DataBlock      *block, +                                   DBusTypeWriter *writer, +                                   int             seed, +                                   int             count); +  dbus_bool_t (* read_multi)      (TestTypeNode   *node, +                                   DBusTypeReader *reader, +                                   int             seed, +                                   int             count); +}; + +struct TestTypeNodeContainerClass +{ +  TestTypeNodeClass base; +}; + +/* FIXME this could be chilled out substantially by unifying + * the basic types into basic_write_value/basic_read_value + * and by merging read_value and set_value into one function + * taking a flag argument. + */ +static dbus_bool_t int32_write_value       (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t int32_read_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t int32_set_value         (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t int32_write_multi       (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed, +                                            int             count); +static dbus_bool_t int32_read_multi        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed, +                                            int             count); +static dbus_bool_t int64_write_value       (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t int64_read_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t int64_set_value         (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t string_write_value      (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t string_read_value       (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t string_set_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t bool_write_value        (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t bool_read_value         (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t bool_set_value          (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t byte_write_value        (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t byte_read_value         (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t byte_set_value          (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t double_write_value      (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t double_read_value       (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t double_set_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t object_path_write_value (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t object_path_read_value  (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t object_path_set_value   (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t signature_write_value   (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t signature_read_value    (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t signature_set_value     (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t struct_write_value      (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t struct_read_value       (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t struct_set_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t struct_build_signature  (TestTypeNode   *node, +                                            DBusString     *str); +static dbus_bool_t array_write_value       (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t array_read_value        (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t array_set_value         (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static dbus_bool_t array_build_signature   (TestTypeNode   *node, +                                            DBusString     *str); +static dbus_bool_t variant_write_value     (TestTypeNode   *node, +                                            DataBlock      *block, +                                            DBusTypeWriter *writer, +                                            int             seed); +static dbus_bool_t variant_read_value      (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            int             seed); +static dbus_bool_t variant_set_value       (TestTypeNode   *node, +                                            DBusTypeReader *reader, +                                            DBusTypeReader *realign_root, +                                            int             seed); +static void        container_destroy       (TestTypeNode   *node); + + +static const TestTypeNodeClass int32_class = { +  DBUS_TYPE_INT32, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  int32_write_value, +  int32_read_value, +  int32_set_value, +  NULL, +  int32_write_multi, +  int32_read_multi +}; + +static const TestTypeNodeClass uint32_class = { +  DBUS_TYPE_UINT32, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  int32_write_value, /* recycle from int32 */ +  int32_read_value,  /* recycle from int32 */ +  int32_set_value,   /* recycle from int32 */ +  NULL, +  int32_write_multi, /* recycle from int32 */ +  int32_read_multi   /* recycle from int32 */ +}; + +static const TestTypeNodeClass int64_class = { +  DBUS_TYPE_INT64, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  int64_write_value, +  int64_read_value, +  int64_set_value, +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */ +}; + +static const TestTypeNodeClass uint64_class = { +  DBUS_TYPE_UINT64, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  int64_write_value, /* recycle from int64 */ +  int64_read_value,  /* recycle from int64 */ +  int64_set_value,   /* recycle from int64 */ +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */ +}; + +static const TestTypeNodeClass string_0_class = { +  DBUS_TYPE_STRING, +  sizeof (TestTypeNode), +  0, /* string length */ +  NULL, +  NULL, +  string_write_value, +  string_read_value, +  string_set_value, +  NULL, +  NULL, +  NULL +}; + +static const TestTypeNodeClass string_1_class = { +  DBUS_TYPE_STRING, +  sizeof (TestTypeNode), +  1, /* string length */ +  NULL, +  NULL, +  string_write_value, +  string_read_value, +  string_set_value, +  NULL, +  NULL, +  NULL +}; + +/* with nul, a len 3 string should fill 4 bytes and thus is "special" */ +static const TestTypeNodeClass string_3_class = { +  DBUS_TYPE_STRING, +  sizeof (TestTypeNode), +  3, /* string length */ +  NULL, +  NULL, +  string_write_value, +  string_read_value, +  string_set_value, +  NULL, +  NULL, +  NULL +}; + +/* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */ +static const TestTypeNodeClass string_8_class = { +  DBUS_TYPE_STRING, +  sizeof (TestTypeNode), +  8, /* string length */ +  NULL, +  NULL, +  string_write_value, +  string_read_value, +  string_set_value, +  NULL, +  NULL, +  NULL +}; + +static const TestTypeNodeClass bool_class = { +  DBUS_TYPE_BOOLEAN, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  bool_write_value, +  bool_read_value, +  bool_set_value, +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */ +}; + +static const TestTypeNodeClass byte_class = { +  DBUS_TYPE_BYTE, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  byte_write_value, +  byte_read_value, +  byte_set_value, +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */ +}; + +static const TestTypeNodeClass double_class = { +  DBUS_TYPE_DOUBLE, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  double_write_value, +  double_read_value, +  double_set_value, +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */ +}; + +static const TestTypeNodeClass object_path_class = { +  DBUS_TYPE_OBJECT_PATH, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  object_path_write_value, +  object_path_read_value, +  object_path_set_value, +  NULL, +  NULL, +  NULL +}; + +static const TestTypeNodeClass signature_class = { +  DBUS_TYPE_SIGNATURE, +  sizeof (TestTypeNode), +  0, +  NULL, +  NULL, +  signature_write_value, +  signature_read_value, +  signature_set_value, +  NULL, +  NULL, +  NULL +}; + +static const TestTypeNodeClass struct_1_class = { +  DBUS_TYPE_STRUCT, +  sizeof (TestTypeNodeContainer), +  1, /* number of times children appear as fields */ +  NULL, +  container_destroy, +  struct_write_value, +  struct_read_value, +  struct_set_value, +  struct_build_signature, +  NULL, +  NULL +}; + +static const TestTypeNodeClass struct_2_class = { +  DBUS_TYPE_STRUCT, +  sizeof (TestTypeNodeContainer), +  2, /* number of times children appear as fields */ +  NULL, +  container_destroy, +  struct_write_value, +  struct_read_value, +  struct_set_value, +  struct_build_signature, +  NULL, +  NULL +}; + +static dbus_bool_t arrays_write_fixed_in_blocks = FALSE; + +static const TestTypeNodeClass array_0_class = { +  DBUS_TYPE_ARRAY, +  sizeof (TestTypeNodeContainer), +  0, /* number of array elements */ +  NULL, +  container_destroy, +  array_write_value, +  array_read_value, +  array_set_value, +  array_build_signature, +  NULL, +  NULL +}; + +static const TestTypeNodeClass array_1_class = { +  DBUS_TYPE_ARRAY, +  sizeof (TestTypeNodeContainer), +  1, /* number of array elements */ +  NULL, +  container_destroy, +  array_write_value, +  array_read_value, +  array_set_value, +  array_build_signature, +  NULL, +  NULL +}; + +static const TestTypeNodeClass array_2_class = { +  DBUS_TYPE_ARRAY, +  sizeof (TestTypeNodeContainer), +  2, /* number of array elements */ +  NULL, +  container_destroy, +  array_write_value, +  array_read_value, +  array_set_value, +  array_build_signature, +  NULL, +  NULL +}; + +static const TestTypeNodeClass array_9_class = { +  DBUS_TYPE_ARRAY, +  sizeof (TestTypeNodeContainer), +  9, /* number of array elements */ +  NULL, +  container_destroy, +  array_write_value, +  array_read_value, +  array_set_value, +  array_build_signature, +  NULL, +  NULL +}; + +static const TestTypeNodeClass variant_class = { +  DBUS_TYPE_VARIANT, +  sizeof (TestTypeNodeContainer), +  0, +  NULL, +  container_destroy, +  variant_write_value, +  variant_read_value, +  variant_set_value, +  NULL, +  NULL, +  NULL +}; + +static const TestTypeNodeClass* const +basic_nodes[] = { +  &int32_class, +  &uint32_class, +  &int64_class, +  &uint64_class, +  &bool_class, +  &byte_class, +  &double_class, +  &string_0_class, +  &string_1_class, +  &string_3_class, +  &string_8_class, +  &object_path_class, +  &signature_class +}; +#define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes)) + +static const TestTypeNodeClass* const +container_nodes[] = { +  &struct_1_class, +  &array_1_class, +  &struct_2_class, +  &array_0_class, +  &array_2_class, +  &variant_class +  /* array_9_class is omitted on purpose, it's too slow; +   * we only use it in one hardcoded test below +   */ +}; +#define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes)) + +static TestTypeNode* +node_new (const TestTypeNodeClass *klass) +{ +  TestTypeNode *node; + +  node = dbus_malloc0 (klass->instance_size); +  if (node == NULL) +    return NULL; + +  node->klass = klass; + +  if (klass->construct) +    { +      if (!(* klass->construct) (node)) +        { +          dbus_free (node); +          return FALSE; +        } +    } + +  return node; +} + +static void +node_destroy (TestTypeNode *node) +{ +  if (node->klass->destroy) +    (* node->klass->destroy) (node); +  dbus_free (node); +} + +static dbus_bool_t +node_write_value (TestTypeNode   *node, +                  DataBlock      *block, +                  DBusTypeWriter *writer, +                  int             seed) +{ +  dbus_bool_t retval; + +  retval = (* node->klass->write_value) (node, block, writer, seed); + +#if 0 +  /* Handy to see where things break, but too expensive to do all the time */ +  data_block_verify (block); +#endif + +  return retval; +} + +static dbus_bool_t +node_read_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 int             seed) +{ +  DBusTypeMark mark; +  DBusTypeReader restored; + +  _dbus_type_reader_save_mark (reader, &mark); + +  if (!(* node->klass->read_value) (node, reader, seed)) +    return FALSE; + +  _dbus_type_reader_init_from_mark (&restored, +                                    reader->byte_order, +                                    reader->type_str, +                                    reader->value_str, +                                    &mark); + +  if (!(* node->klass->read_value) (node, &restored, seed)) +    return FALSE; + +  return TRUE; +} + +/* Warning: if this one fails due to OOM, it has side effects (can + * modify only some of the sub-values). OK in a test suite, but we + * never do this in real code. + */ +static dbus_bool_t +node_set_value (TestTypeNode   *node, +                DBusTypeReader *reader, +                DBusTypeReader *realign_root, +                int             seed) +{ +  if (!(* node->klass->set_value) (node, reader, realign_root, seed)) +    return FALSE; + +  return TRUE; +} + +static dbus_bool_t +node_build_signature (TestTypeNode *node, +                      DBusString   *str) +{ +  if (node->klass->build_signature) +    return (* node->klass->build_signature) (node, str); +  else +    return _dbus_string_append_byte (str, node->klass->typecode); +} + +static dbus_bool_t +node_append_child (TestTypeNode *node, +                   TestTypeNode *child) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + +  _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer)); + +  if (!_dbus_list_append (&container->children, child)) +    _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 */ + +  return TRUE; +} + +static dbus_bool_t +node_write_multi (TestTypeNode   *node, +                  DataBlock      *block, +                  DBusTypeWriter *writer, +                  int             seed, +                  int             n_copies) +{ +  dbus_bool_t retval; + +  _dbus_assert (node->klass->write_multi != NULL); +  retval = (* node->klass->write_multi) (node, block, writer, seed, n_copies); + +#if 0 +  /* Handy to see where things break, but too expensive to do all the time */ +  data_block_verify (block); +#endif + +  return retval; +} + +static dbus_bool_t +node_read_multi (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 int             seed, +                 int             n_copies) +{ +  _dbus_assert (node->klass->read_multi != NULL); + +  if (!(* node->klass->read_multi) (node, reader, seed, n_copies)) +    return FALSE; + +  return TRUE; +} + +static int n_iterations_completed_total = 0; +static int n_iterations_completed_this_test = 0; +static int n_iterations_expected_this_test = 0; + +typedef struct +{ +  const DBusString   *signature; +  DataBlock          *block; +  int                 type_offset; +  TestTypeNode      **nodes; +  int                 n_nodes; +} NodeIterationData; + +static dbus_bool_t +run_test_copy (NodeIterationData *nid) +{ +  DataBlock *src; +  DataBlock dest; +  dbus_bool_t retval; +  DBusTypeReader reader; +  DBusTypeWriter writer; + +  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + +  src = nid->block; + +  retval = FALSE; + +  if (!data_block_init (&dest, src->byte_order, src->initial_offset)) +    return FALSE; + +  data_block_init_reader_writer (src, &reader, NULL); +  data_block_init_reader_writer (&dest, NULL, &writer); + +  /* DBusTypeWriter assumes it's writing into an existing signature, +   * so doesn't add nul on its own. We have to do that. +   */ +  if (!_dbus_string_insert_byte (&dest.signature, +                                 dest.initial_offset, '\0')) +    goto out; + +  if (!_dbus_type_writer_write_reader (&writer, &reader)) +    goto out; + +  /* Data blocks should now be identical */ +  if (!_dbus_string_equal (&src->signature, &dest.signature)) +    { +      _dbus_verbose ("SOURCE\n"); +      _dbus_verbose_bytes_of_string (&src->signature, 0, +                                     _dbus_string_get_length (&src->signature)); +      _dbus_verbose ("DEST\n"); +      _dbus_verbose_bytes_of_string (&dest.signature, 0, +                                     _dbus_string_get_length (&dest.signature)); +      _dbus_assert_not_reached ("signatures did not match"); +    } + +  if (!_dbus_string_equal (&src->body, &dest.body)) +    { +      _dbus_verbose ("SOURCE\n"); +      _dbus_verbose_bytes_of_string (&src->body, 0, +                                     _dbus_string_get_length (&src->body)); +      _dbus_verbose ("DEST\n"); +      _dbus_verbose_bytes_of_string (&dest.body, 0, +                                     _dbus_string_get_length (&dest.body)); +      _dbus_assert_not_reached ("bodies did not match"); +    } + +  retval = TRUE; + + out: + +  data_block_free (&dest); + +  return retval; +} + +static dbus_bool_t +run_test_values_only_write (NodeIterationData *nid) +{ +  DBusTypeReader reader; +  DBusTypeWriter writer; +  int i; +  dbus_bool_t retval; +  int sig_len; + +  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + +  retval = FALSE; + +  data_block_reset (nid->block); + +  sig_len = _dbus_string_get_length (nid->signature); + +  _dbus_type_writer_init_values_only (&writer, +                                      nid->block->byte_order, +                                      nid->signature, 0, +                                      &nid->block->body, +                                      _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES); +  _dbus_type_reader_init (&reader, +                          nid->block->byte_order, +                          nid->signature, 0, +                          &nid->block->body, +                          nid->block->initial_offset); + +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) +        goto out; + +      ++i; +    } + +  /* if we wrote any typecodes then this would fail */ +  _dbus_assert (sig_len == _dbus_string_get_length (nid->signature)); + +  /* But be sure we wrote out the values correctly */ +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_read_value (nid->nodes[i], &reader, i)) +        goto out; + +      if (i + 1 == nid->n_nodes) +        NEXT_EXPECTING_FALSE (&reader); +      else +        NEXT_EXPECTING_TRUE (&reader); + +      ++i; +    } + +  retval = TRUE; + + out: +  data_block_reset (nid->block); +  return retval; +} + +/* offset the seed for setting, so we set different numbers than + * we originally wrote. Don't offset by a huge number since in + * some cases it's value = possibilities[seed % n_possibilities] + * and we don't want to wrap around. bool_from_seed + * is just seed % 2 even. + */ +#define SET_SEED 1 +static dbus_bool_t +run_test_set_values (NodeIterationData *nid) +{ +  DBusTypeReader reader; +  DBusTypeReader realign_root; +  dbus_bool_t retval; +  int i; + +  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + +  retval = FALSE; + +  data_block_init_reader_writer (nid->block, +                                 &reader, NULL); + +  realign_root = reader; + +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_set_value (nid->nodes[i], +                           &reader, &realign_root, +                           i + SET_SEED)) +        goto out; + +      if (i + 1 == nid->n_nodes) +        NEXT_EXPECTING_FALSE (&reader); +      else +        NEXT_EXPECTING_TRUE (&reader); + +      ++i; +    } + +  /* Check that the new values were set */ + +  reader = realign_root; + +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_read_value (nid->nodes[i], &reader, +                            i + SET_SEED)) +        goto out; + +      if (i + 1 == nid->n_nodes) +        NEXT_EXPECTING_FALSE (&reader); +      else +        NEXT_EXPECTING_TRUE (&reader); + +      ++i; +    } + +  retval = TRUE; + + out: +  return retval; +} + +static dbus_bool_t +run_test_delete_values (NodeIterationData *nid) +{ +  DBusTypeReader reader; +  dbus_bool_t retval; +  int t; + +  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + +  retval = FALSE; + +  data_block_init_reader_writer (nid->block, +                                 &reader, NULL); + +  while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) +    { +      /* Right now, deleting only works on array elements.  We delete +       * all array elements, and then verify that there aren't any +       * left. +       */ +      if (t == DBUS_TYPE_ARRAY) +        { +          DBusTypeReader array; +          int n_elements; +          int elem_type; + +          _dbus_type_reader_recurse (&reader, &array); +          n_elements = 0; +          while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) +            { +              n_elements += 1; +              _dbus_type_reader_next (&array); +            } + +          /* reset to start of array */ +          _dbus_type_reader_recurse (&reader, &array); +          _dbus_verbose ("recursing into deletion loop reader.value_pos = %d array.value_pos = %d array.u.start_pos = %d\n", +                         reader.value_pos, array.value_pos, array.u.array.start_pos); +          while ((elem_type = _dbus_type_reader_get_current_type (&array)) != DBUS_TYPE_INVALID) +            { +              /* We don't want to always delete from the same part of the array. */ +              static int cycle = 0; +              int elem; + +              _dbus_assert (n_elements > 0); + +              elem = cycle; +              if (elem == 3 || elem >= n_elements) /* end of array */ +                elem = n_elements - 1; + +              _dbus_verbose ("deleting array element %d of %d type %s cycle %d reader pos %d elem pos %d\n", +                             elem, n_elements, _dbus_type_to_string (elem_type), +                             cycle, reader.value_pos, array.value_pos); +              while (elem > 0) +                { +                  if (!_dbus_type_reader_next (&array)) +                    _dbus_assert_not_reached ("should have had another element\n"); +                  --elem; +                } + +              if (!_dbus_type_reader_delete (&array, &reader)) +                goto out; + +              n_elements -= 1; + +              /* reset */ +              _dbus_type_reader_recurse (&reader, &array); + +              if (cycle > 2) +                cycle = 0; +              else +                cycle += 1; +            } +        } +      _dbus_type_reader_next (&reader); +    } + +  /* Check that there are no array elements left */ +  data_block_init_reader_writer (nid->block, +                                 &reader, NULL); + +  while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) +    { +      _dbus_type_reader_next (&reader); +    } + +  retval = TRUE; + + out: +  return retval; +} + +static dbus_bool_t +run_test_nodes_iteration (void *data) +{ +  NodeIterationData *nid = data; +  DBusTypeReader reader; +  DBusTypeWriter writer; +  int i; +  dbus_bool_t retval; + +  /* Stuff to do: +   * 1. write the value +   * 2. strcmp-compare with the signature we built +   * 3. read the value +   * 4. type-iterate the signature and the value and see if they are the same type-wise +   */ +  retval = FALSE; + +  data_block_init_reader_writer (nid->block, +                                 &reader, &writer); + +  /* DBusTypeWriter assumes it's writing into an existing signature, +   * so doesn't add nul on its own. We have to do that. +   */ +  if (!_dbus_string_insert_byte (&nid->block->signature, +                                 nid->type_offset, '\0')) +    goto out; + +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) +        goto out; + +      ++i; +    } + +  if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature), +                                     &nid->block->signature, nid->type_offset)) +    { +      _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n", +                  _dbus_string_get_const_data (nid->signature), +                  _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0), +                  nid->type_offset); +      _dbus_assert_not_reached ("wrong signature"); +    } + +  i = 0; +  while (i < nid->n_nodes) +    { +      if (!node_read_value (nid->nodes[i], &reader, i)) +        goto out; + +      if (i + 1 == nid->n_nodes) +        NEXT_EXPECTING_FALSE (&reader); +      else +        NEXT_EXPECTING_TRUE (&reader); + +      ++i; +    } + +  if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) +    { +      /* this set values test uses code from copy and +       * values_only_write so would ideally be last so you get a +       * simpler test case for problems with copying or values_only +       * writing; but it also needs an already-written DataBlock so it +       * has to go first. Comment it out if it breaks, and see if the +       * later tests also break - debug them first if so. +       */ +      if (!run_test_set_values (nid)) +        goto out; + +      if (!run_test_delete_values (nid)) +        goto out; + +      if (!run_test_copy (nid)) +        goto out; + +      if (!run_test_values_only_write (nid)) +        goto out; +    } + +  /* FIXME type-iterate both signature and value and compare the resulting +   * tree to the node tree perhaps +   */ + +  retval = TRUE; + + out: + +  data_block_reset (nid->block); + +  return retval; +} + +static void +run_test_nodes_in_one_configuration (TestTypeNode    **nodes, +                                     int               n_nodes, +                                     const DBusString *signature, +                                     int               byte_order, +                                     int               initial_offset) +{ +  DataBlock block; +  NodeIterationData nid; + +  if (!data_block_init (&block, byte_order, initial_offset)) +    _dbus_assert_not_reached ("no memory"); + +  nid.signature = signature; +  nid.block = █ +  nid.type_offset = initial_offset; +  nid.nodes = nodes; +  nid.n_nodes = n_nodes; + +  if (TEST_OOM_HANDLING && +      n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) +    { +      _dbus_test_oom_handling ("running test node", +                               run_test_nodes_iteration, +                               &nid); +    } +  else +    { +      if (!run_test_nodes_iteration (&nid)) +        _dbus_assert_not_reached ("no memory"); +    } + +  data_block_free (&block); +} + +static void +run_test_nodes (TestTypeNode **nodes, +                int            n_nodes) +{ +  int i; +  DBusString signature; + +  if (!_dbus_string_init (&signature)) +    _dbus_assert_not_reached ("no memory"); + +  i = 0; +  while (i < n_nodes) +    { +      if (! node_build_signature (nodes[i], &signature)) +        _dbus_assert_not_reached ("no memory"); + +      ++i; +    } + +  _dbus_verbose (">>> test nodes with signature '%s'\n", +                 _dbus_string_get_const_data (&signature)); + +  i = 0; +  while (i <= MAX_INITIAL_OFFSET) +    { +      run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, +                                           DBUS_LITTLE_ENDIAN, i); +      run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, +                                           DBUS_BIG_ENDIAN, i); + +      ++i; +    } + +  n_iterations_completed_this_test += 1; +  n_iterations_completed_total += 1; + +  if (n_iterations_completed_this_test == n_iterations_expected_this_test) +    { +      fprintf (stderr, " 100%% %d this test (%d cumulative)\n", +               n_iterations_completed_this_test, +               n_iterations_completed_total); +    } +  /* this happens to turn out well with mod == 1 */ +  else if ((n_iterations_completed_this_test % +            (int)(n_iterations_expected_this_test / 10.0)) == 1) +    { +      fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100)); +    } + +  _dbus_string_free (&signature); +} + +#define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS) + +static TestTypeNode* +value_generator (int *ip) +{ +  int i = *ip; +  const TestTypeNodeClass *child_klass; +  const TestTypeNodeClass *container_klass; +  TestTypeNode *child; +  TestTypeNode *node; + +  _dbus_assert (i <= N_VALUES); + +  if (i == N_VALUES) +    { +      return NULL; +    } +  else if (i < N_BASICS) +    { +      node = node_new (basic_nodes[i]); +    } +  else +    { +      /* imagine an array: +       * container 0 of basic 0 +       * container 0 of basic 1 +       * container 0 of basic 2 +       * container 1 of basic 0 +       * container 1 of basic 1 +       * container 1 of basic 2 +       */ +      i -= N_BASICS; + +      container_klass = container_nodes[i / N_BASICS]; +      child_klass = basic_nodes[i % N_BASICS]; + +      node = node_new (container_klass); +      child = node_new (child_klass); + +      node_append_child (node, child); +    } + +  *ip += 1; /* increment the generator */ + +  return node; +} + +static void +make_and_run_values_inside_container (const TestTypeNodeClass *container_klass, +                                      int                      n_nested) +{ +  TestTypeNode *root; +  TestTypeNode *container; +  TestTypeNode *child; +  int i; + +  root = node_new (container_klass); +  container = root; +  for (i = 1; i < n_nested; i++) +    { +      child = node_new (container_klass); +      node_append_child (container, child); +      container = child; +    } + +  /* container should now be the most-nested container */ + +  i = 0; +  while ((child = value_generator (&i))) +    { +      node_append_child (container, child); + +      run_test_nodes (&root, 1); + +      _dbus_list_clear (&((TestTypeNodeContainer*)container)->children); +      node_destroy (child); +    } + +  node_destroy (root); +} + +static void +start_next_test (const char *format, +                 int         expected) +{ +  n_iterations_completed_this_test = 0; +  n_iterations_expected_this_test = expected; + +  fprintf (stderr, ">>> >>> "); +  fprintf (stderr, format, +           n_iterations_expected_this_test); +} + +static void +make_and_run_test_nodes (void) +{ +  int i, j, k, m; + +  /* We try to do this in order of "complicatedness" so that test +   * failures tend to show up in the simplest test case that +   * demonstrates the failure.  There are also some tests that run +   * more than once for this reason, first while going through simple +   * cases, second while going through a broader range of complex +   * cases. +   */ +  /* Each basic node. The basic nodes should include: +   * +   * - each fixed-size type (in such a way that it has different values each time, +   *                         so we can tell if we mix two of them up) +   * - strings of various lengths +   * - object path +   * - signature +   */ +  /* Each container node. The container nodes should include: +   * +   *  struct with 1 and 2 copies of the contained item +   *  array with 0, 1, 2 copies of the contained item +   *  variant +   */ +  /*  Let a "value" be a basic node, or a container containing a single basic node. +   *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic) +   *  When iterating through all values to make combinations, do the basic types +   *  first and the containers second. +   */ +  /* Each item is shown with its number of iterations to complete so +   * we can keep a handle on this unit test +   */ + +  /* FIXME test just an empty body, no types at all */ + +  start_next_test ("Each value by itself %d iterations\n", N_VALUES); +  { +    TestTypeNode *node; +    i = 0; +    while ((node = value_generator (&i))) +      { +        run_test_nodes (&node, 1); + +        node_destroy (node); +      } +  } + +  start_next_test ("Each value by itself with arrays as blocks %d iterations\n", N_VALUES); +  arrays_write_fixed_in_blocks = TRUE; +  { +    TestTypeNode *node; +    i = 0; +    while ((node = value_generator (&i))) +      { +        run_test_nodes (&node, 1); + +        node_destroy (node); +      } +  } +  arrays_write_fixed_in_blocks = FALSE; + +  start_next_test ("All values in one big toplevel %d iteration\n", 1); +  { +    TestTypeNode *nodes[N_VALUES]; + +    i = 0; +    while ((nodes[i] = value_generator (&i))) +      ; + +    run_test_nodes (nodes, N_VALUES); + +    for (i = 0; i < N_VALUES; i++) +      node_destroy (nodes[i]); +  } + +  start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n", +                   N_VALUES * N_VALUES); +  { +    TestTypeNode *nodes[2]; + +    i = 0; +    while ((nodes[0] = value_generator (&i))) +      { +        j = 0; +        while ((nodes[1] = value_generator (&j))) +          { +            run_test_nodes (nodes, 2); + +            node_destroy (nodes[1]); +          } + +        node_destroy (nodes[0]); +      } +  } + +  start_next_test ("Each container containing each value %d iterations\n", +                   N_CONTAINERS * N_VALUES); +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *container_klass = container_nodes[i]; + +      make_and_run_values_inside_container (container_klass, 1); +    } + +  start_next_test ("Each container containing each value with arrays as blocks %d iterations\n", +                   N_CONTAINERS * N_VALUES); +  arrays_write_fixed_in_blocks = TRUE; +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *container_klass = container_nodes[i]; + +      make_and_run_values_inside_container (container_klass, 1); +    } +  arrays_write_fixed_in_blocks = FALSE; + +  start_next_test ("Each container of same container of each value %d iterations\n", +                   N_CONTAINERS * N_VALUES); +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *container_klass = container_nodes[i]; + +      make_and_run_values_inside_container (container_klass, 2); +    } + +  start_next_test ("Each container of same container of same container of each value %d iterations\n", +                   N_CONTAINERS * N_VALUES); +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *container_klass = container_nodes[i]; + +      make_and_run_values_inside_container (container_klass, 3); +    } + +  start_next_test ("Each value,value pair inside a struct %d iterations\n", +                   N_VALUES * N_VALUES); +  { +    TestTypeNode *val1, *val2; +    TestTypeNode *node; + +    node = node_new (&struct_1_class); + +    i = 0; +    while ((val1 = value_generator (&i))) +      { +        j = 0; +        while ((val2 = value_generator (&j))) +          { +            TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + +            node_append_child (node, val1); +            node_append_child (node, val2); + +            run_test_nodes (&node, 1); + +            _dbus_list_clear (&container->children); +            node_destroy (val2); +          } +        node_destroy (val1); +      } +    node_destroy (node); +  } + +  start_next_test ("All values in one big struct %d iteration\n", +                   1); +  { +    TestTypeNode *node; +    TestTypeNode *child; + +    node = node_new (&struct_1_class); + +    i = 0; +    while ((child = value_generator (&i))) +      node_append_child (node, child); + +    run_test_nodes (&node, 1); + +    node_destroy (node); +  } + +  start_next_test ("Each value in a large array %d iterations\n", +                   N_VALUES); +  { +    TestTypeNode *val; +    TestTypeNode *node; + +    node = node_new (&array_9_class); + +    i = 0; +    while ((val = value_generator (&i))) +      { +        TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + +        node_append_child (node, val); + +        run_test_nodes (&node, 1); + +        _dbus_list_clear (&container->children); +        node_destroy (val); +      } + +    node_destroy (node); +  } + +  start_next_test ("Each container of each container of each value %d iterations\n", +                   N_CONTAINERS * N_CONTAINERS * N_VALUES); +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *outer_container_klass = container_nodes[i]; +      TestTypeNode *outer_container = node_new (outer_container_klass); + +      for (j = 0; j < N_CONTAINERS; j++) +        { +          TestTypeNode *child; +          const TestTypeNodeClass *inner_container_klass = container_nodes[j]; +          TestTypeNode *inner_container = node_new (inner_container_klass); + +          node_append_child (outer_container, inner_container); + +          m = 0; +          while ((child = value_generator (&m))) +            { +              node_append_child (inner_container, child); + +              run_test_nodes (&outer_container, 1); + +              _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); +              node_destroy (child); +            } +          _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); +          node_destroy (inner_container); +        } +      node_destroy (outer_container); +    } + +  start_next_test ("Each container of each container of each container of each value %d iterations\n", +                   N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES); +  for (i = 0; i < N_CONTAINERS; i++) +    { +      const TestTypeNodeClass *outer_container_klass = container_nodes[i]; +      TestTypeNode *outer_container = node_new (outer_container_klass); + +      for (j = 0; j < N_CONTAINERS; j++) +        { +          const TestTypeNodeClass *inner_container_klass = container_nodes[j]; +          TestTypeNode *inner_container = node_new (inner_container_klass); + +          node_append_child (outer_container, inner_container); + +          for (k = 0; k < N_CONTAINERS; k++) +            { +              TestTypeNode *child; +              const TestTypeNodeClass *center_container_klass = container_nodes[k]; +              TestTypeNode *center_container = node_new (center_container_klass); + +              node_append_child (inner_container, center_container); + +              m = 0; +              while ((child = value_generator (&m))) +                { +                  node_append_child (center_container, child); + +                  run_test_nodes (&outer_container, 1); + +                  _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children); +                  node_destroy (child); +                } +              _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); +              node_destroy (center_container); +            } +          _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); +          node_destroy (inner_container); +        } +      node_destroy (outer_container); +    } + +#if 0 +  /* This one takes a really long time, so comment it out for now */ +  start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n", +                   N_VALUES * N_VALUES * N_VALUES); +  { +    TestTypeNode *nodes[3]; + +    i = 0; +    while ((nodes[0] = value_generator (&i))) +      { +        j = 0; +        while ((nodes[1] = value_generator (&j))) +          { +            k = 0; +            while ((nodes[2] = value_generator (&k))) +              { +                run_test_nodes (nodes, 3); + +                node_destroy (nodes[2]); +              } +            node_destroy (nodes[1]); +          } +        node_destroy (nodes[0]); +      } +  } +#endif /* #if 0 expensive test */ + +  fprintf (stderr, "%d total iterations of recursive marshaling tests\n", +           n_iterations_completed_total); +  fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n", +           MAX_INITIAL_OFFSET); +  fprintf (stderr, "out of memory handling %s tested\n", +           TEST_OOM_HANDLING ? "was" : "was not"); +} + +dbus_bool_t +_dbus_marshal_recursive_test (void) +{ +  make_and_run_test_nodes (); + +  return TRUE; +} + +/* + * + * + *         Implementations of each type node class + * + * + * + */ +#define MAX_MULTI_COUNT 5 + + +#define SAMPLE_INT32           12345678 +#define SAMPLE_INT32_ALTERNATE 53781429 +static dbus_int32_t +int32_from_seed (int seed) +{ +  /* Generate an integer value that's predictable from seed.  We could +   * just use seed itself, but that would only ever touch one byte of +   * the int so would miss some kinds of bug. +   */ +  dbus_int32_t v; + +  v = 42; /* just to quiet compiler afaik */ +  switch (seed % 5) +    { +    case 0: +      v = SAMPLE_INT32; +      break; +    case 1: +      v = SAMPLE_INT32_ALTERNATE; +      break; +    case 2: +      v = -1; +      break; +    case 3: +      v = _DBUS_INT_MAX; +      break; +    case 4: +      v = 1; +      break; +    } + +  if (seed > 1) +    v *= seed; /* wraps around eventually, which is fine */ + +  return v; +} + +static dbus_bool_t +int32_write_value (TestTypeNode   *node, +                   DataBlock      *block, +                   DBusTypeWriter *writer, +                   int             seed) +{ +  /* also used for uint32 */ +  dbus_int32_t v; + +  v = int32_from_seed (seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v); +} + +static dbus_bool_t +int32_read_value (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  int             seed) +{ +  /* also used for uint32 */ +  dbus_int32_t v; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (dbus_int32_t*) &v); + +  _dbus_assert (v == int32_from_seed (seed)); + +  return TRUE; +} + +static dbus_bool_t +int32_set_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 DBusTypeReader *realign_root, +                 int             seed) +{ +  /* also used for uint32 */ +  dbus_int32_t v; + +  v = int32_from_seed (seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v, +                                      realign_root); +} + +static dbus_bool_t +int32_write_multi (TestTypeNode   *node, +                   DataBlock      *block, +                   DBusTypeWriter *writer, +                   int             seed, +                   int             count) +{ +  /* also used for uint32 */ +  dbus_int32_t values[MAX_MULTI_COUNT]; +  dbus_int32_t *v_ARRAY_INT32 = values; +  int i; + +  for (i = 0; i < count; ++i) +    values[i] = int32_from_seed (seed + i); + +  return _dbus_type_writer_write_fixed_multi (writer, +                                              node->klass->typecode, +                                              &v_ARRAY_INT32, count); +} + +static dbus_bool_t +int32_read_multi (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  int             seed, +                  int             count) +{ +  /* also used for uint32 */ +  dbus_int32_t *values; +  int n_elements; +  int i; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_fixed_multi (reader, +                                      &values, +                                      &n_elements); + +  if (n_elements != count) +    _dbus_warn ("got %d elements expected %d\n", n_elements, count); +  _dbus_assert (n_elements == count); + +  for (i = 0; i < count; i++) +    _dbus_assert (((int)_dbus_unpack_uint32 (reader->byte_order, +                                             (const unsigned char*)values + (i * 4))) == +                  int32_from_seed (seed + i)); + +  return TRUE; +} + +#ifdef DBUS_HAVE_INT64 +static dbus_int64_t +int64_from_seed (int seed) +{ +  dbus_int32_t v32; +  dbus_int64_t v; + +  v32 = int32_from_seed (seed); + +  v = - (dbus_int32_t) ~ v32; +  v |= (((dbus_int64_t)v32) << 32); + +  return v; +} +#endif + +static dbus_bool_t +int64_write_value (TestTypeNode   *node, +                   DataBlock      *block, +                   DBusTypeWriter *writer, +                   int             seed) +{ +#ifdef DBUS_HAVE_INT64 +  /* also used for uint64 */ +  dbus_int64_t v; + +  v = int64_from_seed (seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v); +#else +  return TRUE; +#endif +} + +static dbus_bool_t +int64_read_value (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  int             seed) +{ +#ifdef DBUS_HAVE_INT64 +  /* also used for uint64 */ +  dbus_int64_t v; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (dbus_int64_t*) &v); + +  _dbus_assert (v == int64_from_seed (seed)); + +  return TRUE; +#else +  return TRUE; +#endif +} + +static dbus_bool_t +int64_set_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 DBusTypeReader *realign_root, +                 int             seed) +{ +#ifdef DBUS_HAVE_INT64 +  /* also used for uint64 */ +  dbus_int64_t v; + +  v = int64_from_seed (seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v, +                                      realign_root); +#else +  return TRUE; +#endif +} + +#define MAX_SAMPLE_STRING_LEN 10 +static void +string_from_seed (char *buf, +                  int   len, +                  int   seed) +{ +  int i; +  unsigned char v; + +  _dbus_assert (len < MAX_SAMPLE_STRING_LEN); + +  /* vary the length slightly, though we also have multiple string +   * value types for this, varying it here tests the set_value code +   */ +  switch (seed % 3) +    { +    case 1: +      len += 2; +      break; +    case 2: +      len -= 2; +      break; +    } +  if (len < 0) +    len = 0; + +  v = (unsigned char) ('A' + seed); + +  i = 0; +  while (i < len) +    { +      if (v < 'A' || v > 'z') +        v = 'A'; + +      buf[i] = v; + +      v += 1; +      ++i; +    } + +  buf[i] = '\0'; +} + +static dbus_bool_t +string_write_value (TestTypeNode   *node, +                    DataBlock      *block, +                    DBusTypeWriter *writer, +                    int             seed) +{ +  char buf[MAX_SAMPLE_STRING_LEN]; +  const char *v_string = buf; + +  string_from_seed (buf, node->klass->subclass_detail, +                    seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v_string); +} + +static dbus_bool_t +string_read_value (TestTypeNode   *node, +                   DBusTypeReader *reader, +                   int             seed) +{ +  const char *v; +  char buf[MAX_SAMPLE_STRING_LEN]; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (const char **) &v); + +  string_from_seed (buf, node->klass->subclass_detail, +                    seed); + +  if (strcmp (buf, v) != 0) +    { +      _dbus_warn ("read string '%s' expected '%s'\n", +                  v, buf); +      _dbus_assert_not_reached ("test failed"); +    } + +  return TRUE; +} + +static dbus_bool_t +string_set_value (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  DBusTypeReader *realign_root, +                  int             seed) +{ +  char buf[MAX_SAMPLE_STRING_LEN]; +  const char *v_string = buf; + +  string_from_seed (buf, node->klass->subclass_detail, +                    seed); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + { +   const char *old; +   _dbus_type_reader_read_basic (reader, &old); +   _dbus_verbose ("SETTING new string '%s' len %d in place of '%s' len %d\n", +                  v_string, strlen (v_string), old, strlen (old)); + } +#endif + +  return _dbus_type_reader_set_basic (reader, +                                      &v_string, +                                      realign_root); +} + +#define BOOL_FROM_SEED(seed) (seed % 2) + +static dbus_bool_t +bool_write_value (TestTypeNode   *node, +                  DataBlock      *block, +                  DBusTypeWriter *writer, +                  int             seed) +{ +  unsigned char v; + +  v = BOOL_FROM_SEED (seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v); +} + +static dbus_bool_t +bool_read_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 int             seed) +{ +  unsigned char v; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (unsigned char*) &v); + +  _dbus_assert (v == BOOL_FROM_SEED (seed)); + +  return TRUE; +} + +static dbus_bool_t +bool_set_value (TestTypeNode   *node, +                DBusTypeReader *reader, +                DBusTypeReader *realign_root, +                int             seed) +{ +  unsigned char v; + +  v = BOOL_FROM_SEED (seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v, +                                      realign_root); +} + +#define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed)) + +static dbus_bool_t +byte_write_value (TestTypeNode   *node, +                  DataBlock      *block, +                  DBusTypeWriter *writer, +                  int             seed) +{ +  unsigned char v; + +  v = BYTE_FROM_SEED (seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v); +} + +static dbus_bool_t +byte_read_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 int             seed) +{ +  unsigned char v; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (unsigned char*) &v); + +  _dbus_assert (v == BYTE_FROM_SEED (seed)); + +  return TRUE; +} + + +static dbus_bool_t +byte_set_value (TestTypeNode   *node, +                DBusTypeReader *reader, +                DBusTypeReader *realign_root, +                int             seed) +{ +  unsigned char v; + +  v = BYTE_FROM_SEED (seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v, +                                      realign_root); +} + +static double +double_from_seed (int seed) +{ +  return SAMPLE_INT32 * (double) seed + 0.3; +} + +static dbus_bool_t +double_write_value (TestTypeNode   *node, +                    DataBlock      *block, +                    DBusTypeWriter *writer, +                    int             seed) +{ +  double v; + +  v = double_from_seed (seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v); +} + +static dbus_bool_t +double_read_value (TestTypeNode   *node, +                   DBusTypeReader *reader, +                   int             seed) +{ +  double v; +  double expected; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (double*) &v); + +  expected = double_from_seed (seed); + +  if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected)) +    { +#ifdef DBUS_HAVE_INT64 +      _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n", +                  expected, v, +                  *(dbus_uint64_t*)(char*)&expected, +                  *(dbus_uint64_t*)(char*)&v); +#endif +      _dbus_assert_not_reached ("test failed"); +    } + +  return TRUE; +} + +static dbus_bool_t +double_set_value (TestTypeNode   *node, +                DBusTypeReader *reader, +                DBusTypeReader *realign_root, +                int             seed) +{ +  double v; + +  v = double_from_seed (seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v, +                                      realign_root); +} + +#define MAX_SAMPLE_OBJECT_PATH_LEN 10 +static void +object_path_from_seed (char *buf, +                       int   seed) +{ +  int i; +  unsigned char v; +  int len; + +  len = seed % 9; +  _dbus_assert (len < MAX_SAMPLE_OBJECT_PATH_LEN); + +  v = (unsigned char) ('A' + seed); + +  i = 0; +  while (i + 1 < len) +    { +      if (v < 'A' || v > 'z') +        v = 'A'; + +      buf[i] = '/'; +      ++i; +      buf[i] = v; +      ++i; + +      v += 1; +    } + +  buf[i] = '\0'; +} + +static dbus_bool_t +object_path_write_value (TestTypeNode   *node, +                         DataBlock      *block, +                         DBusTypeWriter *writer, +                         int             seed) +{ +  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; +  const char *v_string = buf; + +  object_path_from_seed (buf, seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v_string); +} + +static dbus_bool_t +object_path_read_value (TestTypeNode   *node, +                        DBusTypeReader *reader, +                        int             seed) +{ +  const char *v; +  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (const char **) &v); + +  object_path_from_seed (buf, seed); + +  if (strcmp (buf, v) != 0) +    { +      _dbus_warn ("read object path '%s' expected '%s'\n", +                  v, buf); +      _dbus_assert_not_reached ("test failed"); +    } + +  return TRUE; +} + +static dbus_bool_t +object_path_set_value (TestTypeNode   *node, +                       DBusTypeReader *reader, +                       DBusTypeReader *realign_root, +                       int             seed) +{ +  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; +  const char *v_string = buf; + +  object_path_from_seed (buf, seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v_string, +                                      realign_root); +} + +#define MAX_SAMPLE_SIGNATURE_LEN 10 +static void +signature_from_seed (char *buf, +                     int   seed) +{ +  int i; +  const char *s; +  /* try to avoid ascending, descending, or alternating length to help find bugs */ +  const char *sample_signatures[] = { +    "asax" +    "", +    "asau(xxxx)", +    "x", +    "ai", +    "a(ii)" +  }; + +  s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)]; + +  for (i = 0; s[i]; i++) +    { +      buf[i] = s[i]; +    } +  buf[i] = '\0'; +} + +static dbus_bool_t +signature_write_value (TestTypeNode   *node, +                       DataBlock      *block, +                       DBusTypeWriter *writer, +                       int             seed) +{ +  char buf[MAX_SAMPLE_SIGNATURE_LEN]; +  const char *v_string = buf; + +  signature_from_seed (buf, seed); + +  return _dbus_type_writer_write_basic (writer, +                                        node->klass->typecode, +                                        &v_string); +} + +static dbus_bool_t +signature_read_value (TestTypeNode   *node, +                      DBusTypeReader *reader, +                      int             seed) +{ +  const char *v; +  char buf[MAX_SAMPLE_SIGNATURE_LEN]; + +  check_expected_type (reader, node->klass->typecode); + +  _dbus_type_reader_read_basic (reader, +                                (const char **) &v); + +  signature_from_seed (buf, seed); + +  if (strcmp (buf, v) != 0) +    { +      _dbus_warn ("read signature value '%s' expected '%s'\n", +                  v, buf); +      _dbus_assert_not_reached ("test failed"); +    } + +  return TRUE; +} + + +static dbus_bool_t +signature_set_value (TestTypeNode   *node, +                     DBusTypeReader *reader, +                     DBusTypeReader *realign_root, +                     int             seed) +{ +  char buf[MAX_SAMPLE_SIGNATURE_LEN]; +  const char *v_string = buf; + +  signature_from_seed (buf, seed); + +  return _dbus_type_reader_set_basic (reader, +                                      &v_string, +                                      realign_root); +} + +static dbus_bool_t +struct_write_value (TestTypeNode   *node, +                    DataBlock      *block, +                    DBusTypeWriter *writer, +                    int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DataBlockState saved; +  DBusTypeWriter sub; +  int i; +  int n_copies; + +  n_copies = node->klass->subclass_detail; + +  _dbus_assert (container->children != NULL); + +  data_block_save (block, &saved); + +  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, +                                  NULL, 0, +                                  &sub)) +    return FALSE; + +  i = 0; +  while (i < n_copies) +    { +      DBusList *link; + +      link = _dbus_list_get_first_link (&container->children); +      while (link != NULL) +        { +          TestTypeNode *child = link->data; +          DBusList *next = _dbus_list_get_next_link (&container->children, link); + +          if (!node_write_value (child, block, &sub, seed + i)) +            { +              data_block_restore (block, &saved); +              return FALSE; +            } + +          link = next; +        } + +      ++i; +    } + +  if (!_dbus_type_writer_unrecurse (writer, &sub)) +    { +      data_block_restore (block, &saved); +      return FALSE; +    } + +  return TRUE; +} + +static dbus_bool_t +struct_read_or_set_value (TestTypeNode   *node, +                          DBusTypeReader *reader, +                          DBusTypeReader *realign_root, +                          int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DBusTypeReader sub; +  int i; +  int n_copies; + +  n_copies = node->klass->subclass_detail; + +  check_expected_type (reader, DBUS_TYPE_STRUCT); + +  _dbus_type_reader_recurse (reader, &sub); + +  i = 0; +  while (i < n_copies) +    { +      DBusList *link; + +      link = _dbus_list_get_first_link (&container->children); +      while (link != NULL) +        { +          TestTypeNode *child = link->data; +          DBusList *next = _dbus_list_get_next_link (&container->children, link); + +          if (realign_root == NULL) +            { +              if (!node_read_value (child, &sub, seed + i)) +                return FALSE; +            } +          else +            { +              if (!node_set_value (child, &sub, realign_root, seed + i)) +                return FALSE; +            } + +          if (i == (n_copies - 1) && next == NULL) +            NEXT_EXPECTING_FALSE (&sub); +          else +            NEXT_EXPECTING_TRUE (&sub); + +          link = next; +        } + +      ++i; +    } + +  return TRUE; +} + +static dbus_bool_t +struct_read_value (TestTypeNode   *node, +                   DBusTypeReader *reader, +                   int             seed) +{ +  return struct_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +struct_set_value (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  DBusTypeReader *realign_root, +                  int             seed) +{ +  return struct_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +struct_build_signature (TestTypeNode   *node, +                        DBusString     *str) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  int i; +  int orig_len; +  int n_copies; + +  n_copies = node->klass->subclass_detail; + +  orig_len = _dbus_string_get_length (str); + +  if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR)) +    goto oom; + +  i = 0; +  while (i < n_copies) +    { +      DBusList *link; + +      link = _dbus_list_get_first_link (&container->children); +      while (link != NULL) +        { +          TestTypeNode *child = link->data; +          DBusList *next = _dbus_list_get_next_link (&container->children, link); + +          if (!node_build_signature (child, str)) +            goto oom; + +          link = next; +        } + +      ++i; +    } + +  if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR)) +    goto oom; + +  return TRUE; + + oom: +  _dbus_string_set_length (str, orig_len); +  return FALSE; +} + +static dbus_bool_t +array_write_value (TestTypeNode   *node, +                   DataBlock      *block, +                   DBusTypeWriter *writer, +                   int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DataBlockState saved; +  DBusTypeWriter sub; +  DBusString element_signature; +  int i; +  int n_copies; +  int element_type; +  TestTypeNode *child; + +  n_copies = node->klass->subclass_detail; + +  _dbus_assert (container->children != NULL); + +  data_block_save (block, &saved); + +  if (!_dbus_string_init (&element_signature)) +    return FALSE; + +  child = _dbus_list_get_first (&container->children); + +  if (!node_build_signature (child, +                             &element_signature)) +    goto oom; + +  element_type = first_type_in_signature (&element_signature, 0); + +  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, +                                  &element_signature, 0, +                                  &sub)) +    goto oom; + +  if (arrays_write_fixed_in_blocks && +      _dbus_type_is_fixed (element_type) && +      child->klass->write_multi) +    { +      if (!node_write_multi (child, block, &sub, seed, n_copies)) +        goto oom; +    } +  else +    { +      i = 0; +      while (i < n_copies) +        { +          DBusList *link; + +          link = _dbus_list_get_first_link (&container->children); +          while (link != NULL) +            { +              TestTypeNode *child = link->data; +              DBusList *next = _dbus_list_get_next_link (&container->children, link); + +              if (!node_write_value (child, block, &sub, seed + i)) +                goto oom; + +              link = next; +            } + +          ++i; +        } +    } + +  if (!_dbus_type_writer_unrecurse (writer, &sub)) +    goto oom; + +  _dbus_string_free (&element_signature); +  return TRUE; + + oom: +  data_block_restore (block, &saved); +  _dbus_string_free (&element_signature); +  return FALSE; +} + +static dbus_bool_t +array_read_or_set_value (TestTypeNode   *node, +                         DBusTypeReader *reader, +                         DBusTypeReader *realign_root, +                         int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DBusTypeReader sub; +  int i; +  int n_copies; +  TestTypeNode *child; + +  n_copies = node->klass->subclass_detail; + +  check_expected_type (reader, DBUS_TYPE_ARRAY); + +  child = _dbus_list_get_first (&container->children); + +  if (n_copies > 0) +    { +      _dbus_type_reader_recurse (reader, &sub); + +      if (realign_root == NULL && arrays_write_fixed_in_blocks && +          _dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && +          child->klass->read_multi) +        { +          if (!node_read_multi (child, &sub, seed, n_copies)) +            return FALSE; +        } +      else +        { +          i = 0; +          while (i < n_copies) +            { +              DBusList *link; + +              link = _dbus_list_get_first_link (&container->children); +              while (link != NULL) +                { +                  TestTypeNode *child = link->data; +                  DBusList *next = _dbus_list_get_next_link (&container->children, link); + +                  _dbus_assert (child->klass->typecode == +                                _dbus_type_reader_get_element_type (reader)); + +                  if (realign_root == NULL) +                    { +                      if (!node_read_value (child, &sub, seed + i)) +                        return FALSE; +                    } +                  else +                    { +                      if (!node_set_value (child, &sub, realign_root, seed + i)) +                        return FALSE; +                    } + +                  if (i == (n_copies - 1) && next == NULL) +                    NEXT_EXPECTING_FALSE (&sub); +                  else +                    NEXT_EXPECTING_TRUE (&sub); + +                  link = next; +                } + +              ++i; +            } +        } +    } + +  return TRUE; +} + +static dbus_bool_t +array_read_value (TestTypeNode   *node, +                  DBusTypeReader *reader, +                  int             seed) +{ +  return array_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +array_set_value (TestTypeNode   *node, +                 DBusTypeReader *reader, +                 DBusTypeReader *realign_root, +                 int             seed) +{ +  return array_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +array_build_signature (TestTypeNode   *node, +                       DBusString     *str) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  int orig_len; + +  orig_len = _dbus_string_get_length (str); + +  if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) +    goto oom; + +  if (!node_build_signature (_dbus_list_get_first (&container->children), +                             str)) +    goto oom; + +  return TRUE; + + oom: +  _dbus_string_set_length (str, orig_len); +  return FALSE; +} + + /* 10 is random just to add another seed that we use in the suite */ +#define VARIANT_SEED 10 + +static dbus_bool_t +variant_write_value (TestTypeNode   *node, +                     DataBlock      *block, +                     DBusTypeWriter *writer, +                     int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DataBlockState saved; +  DBusTypeWriter sub; +  DBusString content_signature; +  TestTypeNode *child; + +  _dbus_assert (container->children != NULL); +  _dbus_assert (_dbus_list_length_is_one (&container->children)); + +  child = _dbus_list_get_first (&container->children); + +  data_block_save (block, &saved); + +  if (!_dbus_string_init (&content_signature)) +    return FALSE; + +  if (!node_build_signature (child, +                             &content_signature)) +    goto oom; + +  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT, +                                  &content_signature, 0, +                                  &sub)) +    goto oom; + +  if (!node_write_value (child, block, &sub, seed + VARIANT_SEED)) +    goto oom; + +  if (!_dbus_type_writer_unrecurse (writer, &sub)) +    goto oom; + +  _dbus_string_free (&content_signature); +  return TRUE; + + oom: +  data_block_restore (block, &saved); +  _dbus_string_free (&content_signature); +  return FALSE; +} + +static dbus_bool_t +variant_read_or_set_value (TestTypeNode   *node, +                           DBusTypeReader *reader, +                           DBusTypeReader *realign_root, +                           int             seed) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DBusTypeReader sub; +  TestTypeNode *child; + +  _dbus_assert (container->children != NULL); +  _dbus_assert (_dbus_list_length_is_one (&container->children)); + +  child = _dbus_list_get_first (&container->children); + +  check_expected_type (reader, DBUS_TYPE_VARIANT); + +  _dbus_type_reader_recurse (reader, &sub); + +  if (realign_root == NULL) +    { +      if (!node_read_value (child, &sub, seed + VARIANT_SEED)) +        return FALSE; +    } +  else +    { +      if (!node_set_value (child, &sub, realign_root, seed + VARIANT_SEED)) +        return FALSE; +    } + +  NEXT_EXPECTING_FALSE (&sub); + +  return TRUE; +} + +static dbus_bool_t +variant_read_value (TestTypeNode   *node, +                    DBusTypeReader *reader, +                    int             seed) +{ +  return variant_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +variant_set_value (TestTypeNode   *node, +                   DBusTypeReader *reader, +                   DBusTypeReader *realign_root, +                   int             seed) +{ +  return variant_read_or_set_value (node, reader, realign_root, seed); +} + +static void +container_destroy (TestTypeNode *node) +{ +  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; +  DBusList *link; + +  link = _dbus_list_get_first_link (&container->children); +  while (link != NULL) +    { +      TestTypeNode *child = link->data; +      DBusList *next = _dbus_list_get_next_link (&container->children, link); + +      node_destroy (child); + +      _dbus_list_free_link (link); + +      link = next; +    } +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 05b827a0..e25fe249 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -2710,2925 +2710,4 @@ _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,  /** @} */ /* end of DBusMarshal group */ -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include "dbus-list.h" -#include <stdio.h> -#include <stdlib.h> - -/* Whether to do the OOM stuff (only with other expensive tests) */ -#define TEST_OOM_HANDLING 0 -/* We do start offset 0 through 9, to get various alignment cases. Still this - * obviously makes the test suite run 10x as slow. - */ -#define MAX_INITIAL_OFFSET 9 - -/* Largest iteration count to test copying, realignment, - * etc. with. i.e. we only test this stuff with some of the smaller - * data sets. - */ -#define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000 - -typedef struct -{ -  int byte_order; -  int initial_offset; -  DBusString signature; -  DBusString body; -} DataBlock; - -typedef struct -{ -  int saved_sig_len; -  int saved_body_len; -} DataBlockState; - -#define N_FENCE_BYTES 5 -#define FENCE_BYTES_STR "abcde" -#define INITIAL_PADDING_BYTE '\0' - -static dbus_bool_t -data_block_init (DataBlock *block, -                 int        byte_order, -                 int        initial_offset) -{ -  if (!_dbus_string_init (&block->signature)) -    return FALSE; - -  if (!_dbus_string_init (&block->body)) -    { -      _dbus_string_free (&block->signature); -      return FALSE; -    } - -  if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset, -                                  INITIAL_PADDING_BYTE) || -      !_dbus_string_insert_bytes (&block->body, 0, initial_offset, -                                  INITIAL_PADDING_BYTE) || -      !_dbus_string_append (&block->signature, FENCE_BYTES_STR) || -      !_dbus_string_append (&block->body, FENCE_BYTES_STR)) -    { -      _dbus_string_free (&block->signature); -      _dbus_string_free (&block->body); -      return FALSE; -    } - -  block->byte_order = byte_order; -  block->initial_offset = initial_offset; - -  return TRUE; -} - -static void -data_block_save (DataBlock      *block, -                 DataBlockState *state) -{ -  state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES; -  state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES; -} - -static void -data_block_restore (DataBlock      *block, -                    DataBlockState *state) -{ -  _dbus_string_delete (&block->signature, -                       state->saved_sig_len, -                       _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES); -  _dbus_string_delete (&block->body, -                       state->saved_body_len, -                       _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES); -} - -static void -data_block_verify (DataBlock *block) -{ -  if (!_dbus_string_ends_with_c_str (&block->signature, -                                     FENCE_BYTES_STR)) -    { -      int offset; - -      offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8; -      if (offset < 0) -        offset = 0; - -      _dbus_verbose_bytes_of_string (&block->signature, -                                     offset, -                                     _dbus_string_get_length (&block->signature) - offset); -      _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature"); -    } -  if (!_dbus_string_ends_with_c_str (&block->body, -                                     FENCE_BYTES_STR)) -    { -      int offset; - -      offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8; -      if (offset < 0) -        offset = 0; - -      _dbus_verbose_bytes_of_string (&block->body, -                                     offset, -                                     _dbus_string_get_length (&block->body) - offset); -      _dbus_assert_not_reached ("block did not verify: bad bytes at end of body"); -    } - -  _dbus_assert (_dbus_string_validate_nul (&block->signature, -                                           0, block->initial_offset)); -  _dbus_assert (_dbus_string_validate_nul (&block->body, -                                           0, block->initial_offset)); -} - -static void -data_block_free (DataBlock *block) -{ -  data_block_verify (block); - -  _dbus_string_free (&block->signature); -  _dbus_string_free (&block->body); -} - -static void -data_block_reset (DataBlock *block) -{ -  data_block_verify (block); - -  _dbus_string_delete (&block->signature, -                       block->initial_offset, -                       _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset); -  _dbus_string_delete (&block->body, -                       block->initial_offset, -                       _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset); - -  data_block_verify (block); -} - -static void -data_block_init_reader_writer (DataBlock      *block, -                               DBusTypeReader *reader, -                               DBusTypeWriter *writer) -{ -  if (reader) -    _dbus_type_reader_init (reader, -                            block->byte_order, -                            &block->signature, -                            block->initial_offset, -                            &block->body, -                            block->initial_offset); - -  if (writer) -    _dbus_type_writer_init (writer, -                            block->byte_order, -                            &block->signature, -                            _dbus_string_get_length (&block->signature) - N_FENCE_BYTES, -                            &block->body, -                            _dbus_string_get_length (&block->body) - N_FENCE_BYTES); -} - -static void -real_check_expected_type (DBusTypeReader *reader, -                          int             expected, -                          const char     *funcname, -                          int             line) -{ -  int t; - -  t = _dbus_type_reader_get_current_type (reader); - -  if (t != expected) -    { -      _dbus_warn ("Read type %s while expecting %s at %s line %d\n", -                  _dbus_type_to_string (t), -                  _dbus_type_to_string (expected), -                  funcname, line); - -      _dbus_assert_not_reached ("read wrong type"); -    } -} - -#define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__) - -#define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \ - {                                                                                      \ -    _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \ -                              _DBUS_FUNCTION_NAME, __LINE__);                           \ -    _dbus_assert_not_reached ("test failed");                                           \ - }                                                                                      \ -} while (0) - -#define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \ - {                                                                                      \ -    _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \ -                              _DBUS_FUNCTION_NAME, __LINE__);                           \ -    _dbus_assert_not_reached ("test failed");                                           \ - }                                                                                      \ - check_expected_type (reader, DBUS_TYPE_INVALID);                                       \ -} while (0) - -typedef struct TestTypeNode               TestTypeNode; -typedef struct TestTypeNodeClass          TestTypeNodeClass; -typedef struct TestTypeNodeContainer      TestTypeNodeContainer; -typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass; - -struct TestTypeNode -{ -  const TestTypeNodeClass *klass; -}; - -struct TestTypeNodeContainer -{ -  TestTypeNode base; -  DBusList    *children; -}; - -struct TestTypeNodeClass -{ -  int typecode; - -  int instance_size; - -  int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */ - -  dbus_bool_t   (* construct)     (TestTypeNode   *node); -  void          (* destroy)       (TestTypeNode   *node); - -  dbus_bool_t (* write_value)     (TestTypeNode   *node, -                                   DataBlock      *block, -                                   DBusTypeWriter *writer, -                                   int             seed); -  dbus_bool_t (* read_value)      (TestTypeNode   *node, -                                   DBusTypeReader *reader, -                                   int             seed); -  dbus_bool_t (* set_value)       (TestTypeNode   *node, -                                   DBusTypeReader *reader, -                                   DBusTypeReader *realign_root, -                                   int             seed); -  dbus_bool_t (* build_signature) (TestTypeNode   *node, -                                   DBusString     *str); -  dbus_bool_t (* write_multi)     (TestTypeNode   *node, -                                   DataBlock      *block, -                                   DBusTypeWriter *writer, -                                   int             seed, -                                   int             count); -  dbus_bool_t (* read_multi)      (TestTypeNode   *node, -                                   DBusTypeReader *reader, -                                   int             seed, -                                   int             count); -}; - -struct TestTypeNodeContainerClass -{ -  TestTypeNodeClass base; -}; - -/* FIXME this could be chilled out substantially by unifying - * the basic types into basic_write_value/basic_read_value - * and by merging read_value and set_value into one function - * taking a flag argument. - */ -static dbus_bool_t int32_write_value       (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t int32_read_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t int32_set_value         (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t int32_write_multi       (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed, -                                            int             count); -static dbus_bool_t int32_read_multi        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed, -                                            int             count); -static dbus_bool_t int64_write_value       (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t int64_read_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t int64_set_value         (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t string_write_value      (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t string_read_value       (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t string_set_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t bool_write_value        (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t bool_read_value         (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t bool_set_value          (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t byte_write_value        (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t byte_read_value         (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t byte_set_value          (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t double_write_value      (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t double_read_value       (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t double_set_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t object_path_write_value (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t object_path_read_value  (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t object_path_set_value   (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t signature_write_value   (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t signature_read_value    (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t signature_set_value     (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t struct_write_value      (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t struct_read_value       (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t struct_set_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t struct_build_signature  (TestTypeNode   *node, -                                            DBusString     *str); -static dbus_bool_t array_write_value       (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t array_read_value        (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t array_set_value         (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static dbus_bool_t array_build_signature   (TestTypeNode   *node, -                                            DBusString     *str); -static dbus_bool_t variant_write_value     (TestTypeNode   *node, -                                            DataBlock      *block, -                                            DBusTypeWriter *writer, -                                            int             seed); -static dbus_bool_t variant_read_value      (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            int             seed); -static dbus_bool_t variant_set_value       (TestTypeNode   *node, -                                            DBusTypeReader *reader, -                                            DBusTypeReader *realign_root, -                                            int             seed); -static void        container_destroy       (TestTypeNode   *node); - - -static const TestTypeNodeClass int32_class = { -  DBUS_TYPE_INT32, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  int32_write_value, -  int32_read_value, -  int32_set_value, -  NULL, -  int32_write_multi, -  int32_read_multi -}; - -static const TestTypeNodeClass uint32_class = { -  DBUS_TYPE_UINT32, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  int32_write_value, /* recycle from int32 */ -  int32_read_value,  /* recycle from int32 */ -  int32_set_value,   /* recycle from int32 */ -  NULL, -  int32_write_multi, /* recycle from int32 */ -  int32_read_multi   /* recycle from int32 */ -}; - -static const TestTypeNodeClass int64_class = { -  DBUS_TYPE_INT64, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  int64_write_value, -  int64_read_value, -  int64_set_value, -  NULL, -  NULL, /* FIXME */ -  NULL  /* FIXME */ -}; - -static const TestTypeNodeClass uint64_class = { -  DBUS_TYPE_UINT64, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  int64_write_value, /* recycle from int64 */ -  int64_read_value,  /* recycle from int64 */ -  int64_set_value,   /* recycle from int64 */ -  NULL, -  NULL, /* FIXME */ -  NULL  /* FIXME */ -}; - -static const TestTypeNodeClass string_0_class = { -  DBUS_TYPE_STRING, -  sizeof (TestTypeNode), -  0, /* string length */ -  NULL, -  NULL, -  string_write_value, -  string_read_value, -  string_set_value, -  NULL, -  NULL, -  NULL -}; - -static const TestTypeNodeClass string_1_class = { -  DBUS_TYPE_STRING, -  sizeof (TestTypeNode), -  1, /* string length */ -  NULL, -  NULL, -  string_write_value, -  string_read_value, -  string_set_value, -  NULL, -  NULL, -  NULL -}; - -/* with nul, a len 3 string should fill 4 bytes and thus is "special" */ -static const TestTypeNodeClass string_3_class = { -  DBUS_TYPE_STRING, -  sizeof (TestTypeNode), -  3, /* string length */ -  NULL, -  NULL, -  string_write_value, -  string_read_value, -  string_set_value, -  NULL, -  NULL, -  NULL -}; - -/* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */ -static const TestTypeNodeClass string_8_class = { -  DBUS_TYPE_STRING, -  sizeof (TestTypeNode), -  8, /* string length */ -  NULL, -  NULL, -  string_write_value, -  string_read_value, -  string_set_value, -  NULL, -  NULL, -  NULL -}; - -static const TestTypeNodeClass bool_class = { -  DBUS_TYPE_BOOLEAN, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  bool_write_value, -  bool_read_value, -  bool_set_value, -  NULL, -  NULL, /* FIXME */ -  NULL  /* FIXME */ -}; - -static const TestTypeNodeClass byte_class = { -  DBUS_TYPE_BYTE, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  byte_write_value, -  byte_read_value, -  byte_set_value, -  NULL, -  NULL, /* FIXME */ -  NULL  /* FIXME */ -}; - -static const TestTypeNodeClass double_class = { -  DBUS_TYPE_DOUBLE, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  double_write_value, -  double_read_value, -  double_set_value, -  NULL, -  NULL, /* FIXME */ -  NULL  /* FIXME */ -}; - -static const TestTypeNodeClass object_path_class = { -  DBUS_TYPE_OBJECT_PATH, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  object_path_write_value, -  object_path_read_value, -  object_path_set_value, -  NULL, -  NULL, -  NULL -}; - -static const TestTypeNodeClass signature_class = { -  DBUS_TYPE_SIGNATURE, -  sizeof (TestTypeNode), -  0, -  NULL, -  NULL, -  signature_write_value, -  signature_read_value, -  signature_set_value, -  NULL, -  NULL, -  NULL -}; - -static const TestTypeNodeClass struct_1_class = { -  DBUS_TYPE_STRUCT, -  sizeof (TestTypeNodeContainer), -  1, /* number of times children appear as fields */ -  NULL, -  container_destroy, -  struct_write_value, -  struct_read_value, -  struct_set_value, -  struct_build_signature, -  NULL, -  NULL -}; - -static const TestTypeNodeClass struct_2_class = { -  DBUS_TYPE_STRUCT, -  sizeof (TestTypeNodeContainer), -  2, /* number of times children appear as fields */ -  NULL, -  container_destroy, -  struct_write_value, -  struct_read_value, -  struct_set_value, -  struct_build_signature, -  NULL, -  NULL -}; - -static dbus_bool_t arrays_write_fixed_in_blocks = FALSE; - -static const TestTypeNodeClass array_0_class = { -  DBUS_TYPE_ARRAY, -  sizeof (TestTypeNodeContainer), -  0, /* number of array elements */ -  NULL, -  container_destroy, -  array_write_value, -  array_read_value, -  array_set_value, -  array_build_signature, -  NULL, -  NULL -}; - -static const TestTypeNodeClass array_1_class = { -  DBUS_TYPE_ARRAY, -  sizeof (TestTypeNodeContainer), -  1, /* number of array elements */ -  NULL, -  container_destroy, -  array_write_value, -  array_read_value, -  array_set_value, -  array_build_signature, -  NULL, -  NULL -}; - -static const TestTypeNodeClass array_2_class = { -  DBUS_TYPE_ARRAY, -  sizeof (TestTypeNodeContainer), -  2, /* number of array elements */ -  NULL, -  container_destroy, -  array_write_value, -  array_read_value, -  array_set_value, -  array_build_signature, -  NULL, -  NULL -}; - -static const TestTypeNodeClass array_9_class = { -  DBUS_TYPE_ARRAY, -  sizeof (TestTypeNodeContainer), -  9, /* number of array elements */ -  NULL, -  container_destroy, -  array_write_value, -  array_read_value, -  array_set_value, -  array_build_signature, -  NULL, -  NULL -}; - -static const TestTypeNodeClass variant_class = { -  DBUS_TYPE_VARIANT, -  sizeof (TestTypeNodeContainer), -  0, -  NULL, -  container_destroy, -  variant_write_value, -  variant_read_value, -  variant_set_value, -  NULL, -  NULL, -  NULL -}; - -static const TestTypeNodeClass* const -basic_nodes[] = { -  &int32_class, -  &uint32_class, -  &int64_class, -  &uint64_class, -  &bool_class, -  &byte_class, -  &double_class, -  &string_0_class, -  &string_1_class, -  &string_3_class, -  &string_8_class, -  &object_path_class, -  &signature_class -}; -#define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes)) - -static const TestTypeNodeClass* const -container_nodes[] = { -  &struct_1_class, -  &array_1_class, -  &struct_2_class, -  &array_0_class, -  &array_2_class, -  &variant_class -  /* array_9_class is omitted on purpose, it's too slow; -   * we only use it in one hardcoded test below -   */ -}; -#define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes)) - -static TestTypeNode* -node_new (const TestTypeNodeClass *klass) -{ -  TestTypeNode *node; - -  node = dbus_malloc0 (klass->instance_size); -  if (node == NULL) -    return NULL; - -  node->klass = klass; - -  if (klass->construct) -    { -      if (!(* klass->construct) (node)) -        { -          dbus_free (node); -          return FALSE; -        } -    } - -  return node; -} - -static void -node_destroy (TestTypeNode *node) -{ -  if (node->klass->destroy) -    (* node->klass->destroy) (node); -  dbus_free (node); -} - -static dbus_bool_t -node_write_value (TestTypeNode   *node, -                  DataBlock      *block, -                  DBusTypeWriter *writer, -                  int             seed) -{ -  dbus_bool_t retval; - -  retval = (* node->klass->write_value) (node, block, writer, seed); - -#if 0 -  /* Handy to see where things break, but too expensive to do all the time */ -  data_block_verify (block); -#endif - -  return retval; -} - -static dbus_bool_t -node_read_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 int             seed) -{ -  DBusTypeMark mark; -  DBusTypeReader restored; - -  _dbus_type_reader_save_mark (reader, &mark); - -  if (!(* node->klass->read_value) (node, reader, seed)) -    return FALSE; - -  _dbus_type_reader_init_from_mark (&restored, -                                    reader->byte_order, -                                    reader->type_str, -                                    reader->value_str, -                                    &mark); - -  if (!(* node->klass->read_value) (node, &restored, seed)) -    return FALSE; - -  return TRUE; -} - -/* Warning: if this one fails due to OOM, it has side effects (can - * modify only some of the sub-values). OK in a test suite, but we - * never do this in real code. - */ -static dbus_bool_t -node_set_value (TestTypeNode   *node, -                DBusTypeReader *reader, -                DBusTypeReader *realign_root, -                int             seed) -{ -  if (!(* node->klass->set_value) (node, reader, realign_root, seed)) -    return FALSE; - -  return TRUE; -} - -static dbus_bool_t -node_build_signature (TestTypeNode *node, -                      DBusString   *str) -{ -  if (node->klass->build_signature) -    return (* node->klass->build_signature) (node, str); -  else -    return _dbus_string_append_byte (str, node->klass->typecode); -} - -static dbus_bool_t -node_append_child (TestTypeNode *node, -                   TestTypeNode *child) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; - -  _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer)); - -  if (!_dbus_list_append (&container->children, child)) -    _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 */ - -  return TRUE; -} - -static dbus_bool_t -node_write_multi (TestTypeNode   *node, -                  DataBlock      *block, -                  DBusTypeWriter *writer, -                  int             seed, -                  int             n_copies) -{ -  dbus_bool_t retval; - -  _dbus_assert (node->klass->write_multi != NULL); -  retval = (* node->klass->write_multi) (node, block, writer, seed, n_copies); - -#if 0 -  /* Handy to see where things break, but too expensive to do all the time */ -  data_block_verify (block); -#endif - -  return retval; -} - -static dbus_bool_t -node_read_multi (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 int             seed, -                 int             n_copies) -{ -  _dbus_assert (node->klass->read_multi != NULL); - -  if (!(* node->klass->read_multi) (node, reader, seed, n_copies)) -    return FALSE; - -  return TRUE; -} - -static int n_iterations_completed_total = 0; -static int n_iterations_completed_this_test = 0; -static int n_iterations_expected_this_test = 0; - -typedef struct -{ -  const DBusString   *signature; -  DataBlock          *block; -  int                 type_offset; -  TestTypeNode      **nodes; -  int                 n_nodes; -} NodeIterationData; - -static dbus_bool_t -run_test_copy (NodeIterationData *nid) -{ -  DataBlock *src; -  DataBlock dest; -  dbus_bool_t retval; -  DBusTypeReader reader; -  DBusTypeWriter writer; - -  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - -  src = nid->block; - -  retval = FALSE; - -  if (!data_block_init (&dest, src->byte_order, src->initial_offset)) -    return FALSE; - -  data_block_init_reader_writer (src, &reader, NULL); -  data_block_init_reader_writer (&dest, NULL, &writer); - -  /* DBusTypeWriter assumes it's writing into an existing signature, -   * so doesn't add nul on its own. We have to do that. -   */ -  if (!_dbus_string_insert_byte (&dest.signature, -                                 dest.initial_offset, '\0')) -    goto out; - -  if (!_dbus_type_writer_write_reader (&writer, &reader)) -    goto out; - -  /* Data blocks should now be identical */ -  if (!_dbus_string_equal (&src->signature, &dest.signature)) -    { -      _dbus_verbose ("SOURCE\n"); -      _dbus_verbose_bytes_of_string (&src->signature, 0, -                                     _dbus_string_get_length (&src->signature)); -      _dbus_verbose ("DEST\n"); -      _dbus_verbose_bytes_of_string (&dest.signature, 0, -                                     _dbus_string_get_length (&dest.signature)); -      _dbus_assert_not_reached ("signatures did not match"); -    } - -  if (!_dbus_string_equal (&src->body, &dest.body)) -    { -      _dbus_verbose ("SOURCE\n"); -      _dbus_verbose_bytes_of_string (&src->body, 0, -                                     _dbus_string_get_length (&src->body)); -      _dbus_verbose ("DEST\n"); -      _dbus_verbose_bytes_of_string (&dest.body, 0, -                                     _dbus_string_get_length (&dest.body)); -      _dbus_assert_not_reached ("bodies did not match"); -    } - -  retval = TRUE; - - out: - -  data_block_free (&dest); - -  return retval; -} - -static dbus_bool_t -run_test_values_only_write (NodeIterationData *nid) -{ -  DBusTypeReader reader; -  DBusTypeWriter writer; -  int i; -  dbus_bool_t retval; -  int sig_len; - -  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - -  retval = FALSE; - -  data_block_reset (nid->block); - -  sig_len = _dbus_string_get_length (nid->signature); - -  _dbus_type_writer_init_values_only (&writer, -                                      nid->block->byte_order, -                                      nid->signature, 0, -                                      &nid->block->body, -                                      _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES); -  _dbus_type_reader_init (&reader, -                          nid->block->byte_order, -                          nid->signature, 0, -                          &nid->block->body, -                          nid->block->initial_offset); - -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) -        goto out; - -      ++i; -    } - -  /* if we wrote any typecodes then this would fail */ -  _dbus_assert (sig_len == _dbus_string_get_length (nid->signature)); - -  /* But be sure we wrote out the values correctly */ -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_read_value (nid->nodes[i], &reader, i)) -        goto out; - -      if (i + 1 == nid->n_nodes) -        NEXT_EXPECTING_FALSE (&reader); -      else -        NEXT_EXPECTING_TRUE (&reader); - -      ++i; -    } - -  retval = TRUE; - - out: -  data_block_reset (nid->block); -  return retval; -} - -/* offset the seed for setting, so we set different numbers than - * we originally wrote. Don't offset by a huge number since in - * some cases it's value = possibilities[seed % n_possibilities] - * and we don't want to wrap around. bool_from_seed - * is just seed % 2 even. - */ -#define SET_SEED 1 -static dbus_bool_t -run_test_set_values (NodeIterationData *nid) -{ -  DBusTypeReader reader; -  DBusTypeReader realign_root; -  dbus_bool_t retval; -  int i; - -  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - -  retval = FALSE; - -  data_block_init_reader_writer (nid->block, -                                 &reader, NULL); - -  realign_root = reader; - -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_set_value (nid->nodes[i], -                           &reader, &realign_root, -                           i + SET_SEED)) -        goto out; - -      if (i + 1 == nid->n_nodes) -        NEXT_EXPECTING_FALSE (&reader); -      else -        NEXT_EXPECTING_TRUE (&reader); - -      ++i; -    } - -  /* Check that the new values were set */ - -  reader = realign_root; - -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_read_value (nid->nodes[i], &reader, -                            i + SET_SEED)) -        goto out; - -      if (i + 1 == nid->n_nodes) -        NEXT_EXPECTING_FALSE (&reader); -      else -        NEXT_EXPECTING_TRUE (&reader); - -      ++i; -    } - -  retval = TRUE; - - out: -  return retval; -} - -static dbus_bool_t -run_test_delete_values (NodeIterationData *nid) -{ -  DBusTypeReader reader; -  dbus_bool_t retval; -  int t; - -  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - -  retval = FALSE; - -  data_block_init_reader_writer (nid->block, -                                 &reader, NULL); - -  while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) -    { -      /* Right now, deleting only works on array elements.  We delete -       * all array elements, and then verify that there aren't any -       * left. -       */ -      if (t == DBUS_TYPE_ARRAY) -        { -          DBusTypeReader array; -          int n_elements; -          int elem_type; - -          _dbus_type_reader_recurse (&reader, &array); -          n_elements = 0; -          while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) -            { -              n_elements += 1; -              _dbus_type_reader_next (&array); -            } - -          /* reset to start of array */ -          _dbus_type_reader_recurse (&reader, &array); -          _dbus_verbose ("recursing into deletion loop reader.value_pos = %d array.value_pos = %d array.u.start_pos = %d\n", -                         reader.value_pos, array.value_pos, array.u.array.start_pos); -          while ((elem_type = _dbus_type_reader_get_current_type (&array)) != DBUS_TYPE_INVALID) -            { -              /* We don't want to always delete from the same part of the array. */ -              static int cycle = 0; -              int elem; - -              _dbus_assert (n_elements > 0); - -              elem = cycle; -              if (elem == 3 || elem >= n_elements) /* end of array */ -                elem = n_elements - 1; - -              _dbus_verbose ("deleting array element %d of %d type %s cycle %d reader pos %d elem pos %d\n", -                             elem, n_elements, _dbus_type_to_string (elem_type), -                             cycle, reader.value_pos, array.value_pos); -              while (elem > 0) -                { -                  if (!_dbus_type_reader_next (&array)) -                    _dbus_assert_not_reached ("should have had another element\n"); -                  --elem; -                } - -              if (!_dbus_type_reader_delete (&array, &reader)) -                goto out; - -              n_elements -= 1; - -              /* reset */ -              _dbus_type_reader_recurse (&reader, &array); - -              if (cycle > 2) -                cycle = 0; -              else -                cycle += 1; -            } -        } -      _dbus_type_reader_next (&reader); -    } - -  /* Check that there are no array elements left */ -  data_block_init_reader_writer (nid->block, -                                 &reader, NULL); - -  while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) -    { -      _dbus_type_reader_next (&reader); -    } - -  retval = TRUE; - - out: -  return retval; -} - -static dbus_bool_t -run_test_nodes_iteration (void *data) -{ -  NodeIterationData *nid = data; -  DBusTypeReader reader; -  DBusTypeWriter writer; -  int i; -  dbus_bool_t retval; - -  /* Stuff to do: -   * 1. write the value -   * 2. strcmp-compare with the signature we built -   * 3. read the value -   * 4. type-iterate the signature and the value and see if they are the same type-wise -   */ -  retval = FALSE; - -  data_block_init_reader_writer (nid->block, -                                 &reader, &writer); - -  /* DBusTypeWriter assumes it's writing into an existing signature, -   * so doesn't add nul on its own. We have to do that. -   */ -  if (!_dbus_string_insert_byte (&nid->block->signature, -                                 nid->type_offset, '\0')) -    goto out; - -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) -        goto out; - -      ++i; -    } - -  if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature), -                                     &nid->block->signature, nid->type_offset)) -    { -      _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n", -                  _dbus_string_get_const_data (nid->signature), -                  _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0), -                  nid->type_offset); -      _dbus_assert_not_reached ("wrong signature"); -    } - -  i = 0; -  while (i < nid->n_nodes) -    { -      if (!node_read_value (nid->nodes[i], &reader, i)) -        goto out; - -      if (i + 1 == nid->n_nodes) -        NEXT_EXPECTING_FALSE (&reader); -      else -        NEXT_EXPECTING_TRUE (&reader); - -      ++i; -    } - -  if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) -    { -      /* this set values test uses code from copy and -       * values_only_write so would ideally be last so you get a -       * simpler test case for problems with copying or values_only -       * writing; but it also needs an already-written DataBlock so it -       * has to go first. Comment it out if it breaks, and see if the -       * later tests also break - debug them first if so. -       */ -      if (!run_test_set_values (nid)) -        goto out; - -      if (!run_test_delete_values (nid)) -        goto out; - -      if (!run_test_copy (nid)) -        goto out; - -      if (!run_test_values_only_write (nid)) -        goto out; -    } - -  /* FIXME type-iterate both signature and value and compare the resulting -   * tree to the node tree perhaps -   */ - -  retval = TRUE; - - out: - -  data_block_reset (nid->block); - -  return retval; -} - -static void -run_test_nodes_in_one_configuration (TestTypeNode    **nodes, -                                     int               n_nodes, -                                     const DBusString *signature, -                                     int               byte_order, -                                     int               initial_offset) -{ -  DataBlock block; -  NodeIterationData nid; - -  if (!data_block_init (&block, byte_order, initial_offset)) -    _dbus_assert_not_reached ("no memory"); - -  nid.signature = signature; -  nid.block = █ -  nid.type_offset = initial_offset; -  nid.nodes = nodes; -  nid.n_nodes = n_nodes; - -  if (TEST_OOM_HANDLING && -      n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) -    { -      _dbus_test_oom_handling ("running test node", -                               run_test_nodes_iteration, -                               &nid); -    } -  else -    { -      if (!run_test_nodes_iteration (&nid)) -        _dbus_assert_not_reached ("no memory"); -    } - -  data_block_free (&block); -} - -static void -run_test_nodes (TestTypeNode **nodes, -                int            n_nodes) -{ -  int i; -  DBusString signature; - -  if (!_dbus_string_init (&signature)) -    _dbus_assert_not_reached ("no memory"); - -  i = 0; -  while (i < n_nodes) -    { -      if (! node_build_signature (nodes[i], &signature)) -        _dbus_assert_not_reached ("no memory"); - -      ++i; -    } - -  _dbus_verbose (">>> test nodes with signature '%s'\n", -                 _dbus_string_get_const_data (&signature)); - -  i = 0; -  while (i <= MAX_INITIAL_OFFSET) -    { -      run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, -                                           DBUS_LITTLE_ENDIAN, i); -      run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, -                                           DBUS_BIG_ENDIAN, i); - -      ++i; -    } - -  n_iterations_completed_this_test += 1; -  n_iterations_completed_total += 1; - -  if (n_iterations_completed_this_test == n_iterations_expected_this_test) -    { -      fprintf (stderr, " 100%% %d this test (%d cumulative)\n", -               n_iterations_completed_this_test, -               n_iterations_completed_total); -    } -  /* this happens to turn out well with mod == 1 */ -  else if ((n_iterations_completed_this_test % -            (int)(n_iterations_expected_this_test / 10.0)) == 1) -    { -      fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100)); -    } - -  _dbus_string_free (&signature); -} - -#define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS) - -static TestTypeNode* -value_generator (int *ip) -{ -  int i = *ip; -  const TestTypeNodeClass *child_klass; -  const TestTypeNodeClass *container_klass; -  TestTypeNode *child; -  TestTypeNode *node; - -  _dbus_assert (i <= N_VALUES); - -  if (i == N_VALUES) -    { -      return NULL; -    } -  else if (i < N_BASICS) -    { -      node = node_new (basic_nodes[i]); -    } -  else -    { -      /* imagine an array: -       * container 0 of basic 0 -       * container 0 of basic 1 -       * container 0 of basic 2 -       * container 1 of basic 0 -       * container 1 of basic 1 -       * container 1 of basic 2 -       */ -      i -= N_BASICS; - -      container_klass = container_nodes[i / N_BASICS]; -      child_klass = basic_nodes[i % N_BASICS]; - -      node = node_new (container_klass); -      child = node_new (child_klass); - -      node_append_child (node, child); -    } - -  *ip += 1; /* increment the generator */ - -  return node; -} - -static void -make_and_run_values_inside_container (const TestTypeNodeClass *container_klass, -                                      int                      n_nested) -{ -  TestTypeNode *root; -  TestTypeNode *container; -  TestTypeNode *child; -  int i; - -  root = node_new (container_klass); -  container = root; -  for (i = 1; i < n_nested; i++) -    { -      child = node_new (container_klass); -      node_append_child (container, child); -      container = child; -    } - -  /* container should now be the most-nested container */ - -  i = 0; -  while ((child = value_generator (&i))) -    { -      node_append_child (container, child); - -      run_test_nodes (&root, 1); - -      _dbus_list_clear (&((TestTypeNodeContainer*)container)->children); -      node_destroy (child); -    } - -  node_destroy (root); -} - -static void -start_next_test (const char *format, -                 int         expected) -{ -  n_iterations_completed_this_test = 0; -  n_iterations_expected_this_test = expected; - -  fprintf (stderr, ">>> >>> "); -  fprintf (stderr, format, -           n_iterations_expected_this_test); -} - -static void -make_and_run_test_nodes (void) -{ -  int i, j, k, m; - -  /* We try to do this in order of "complicatedness" so that test -   * failures tend to show up in the simplest test case that -   * demonstrates the failure.  There are also some tests that run -   * more than once for this reason, first while going through simple -   * cases, second while going through a broader range of complex -   * cases. -   */ -  /* Each basic node. The basic nodes should include: -   * -   * - each fixed-size type (in such a way that it has different values each time, -   *                         so we can tell if we mix two of them up) -   * - strings of various lengths -   * - object path -   * - signature -   */ -  /* Each container node. The container nodes should include: -   * -   *  struct with 1 and 2 copies of the contained item -   *  array with 0, 1, 2 copies of the contained item -   *  variant -   */ -  /*  Let a "value" be a basic node, or a container containing a single basic node. -   *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic) -   *  When iterating through all values to make combinations, do the basic types -   *  first and the containers second. -   */ -  /* Each item is shown with its number of iterations to complete so -   * we can keep a handle on this unit test -   */ - -  /* FIXME test just an empty body, no types at all */ - -  start_next_test ("Each value by itself %d iterations\n", N_VALUES); -  { -    TestTypeNode *node; -    i = 0; -    while ((node = value_generator (&i))) -      { -        run_test_nodes (&node, 1); - -        node_destroy (node); -      } -  } - -  start_next_test ("Each value by itself with arrays as blocks %d iterations\n", N_VALUES); -  arrays_write_fixed_in_blocks = TRUE; -  { -    TestTypeNode *node; -    i = 0; -    while ((node = value_generator (&i))) -      { -        run_test_nodes (&node, 1); - -        node_destroy (node); -      } -  } -  arrays_write_fixed_in_blocks = FALSE; - -  start_next_test ("All values in one big toplevel %d iteration\n", 1); -  { -    TestTypeNode *nodes[N_VALUES]; - -    i = 0; -    while ((nodes[i] = value_generator (&i))) -      ; - -    run_test_nodes (nodes, N_VALUES); - -    for (i = 0; i < N_VALUES; i++) -      node_destroy (nodes[i]); -  } - -  start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n", -                   N_VALUES * N_VALUES); -  { -    TestTypeNode *nodes[2]; - -    i = 0; -    while ((nodes[0] = value_generator (&i))) -      { -        j = 0; -        while ((nodes[1] = value_generator (&j))) -          { -            run_test_nodes (nodes, 2); - -            node_destroy (nodes[1]); -          } - -        node_destroy (nodes[0]); -      } -  } - -  start_next_test ("Each container containing each value %d iterations\n", -                   N_CONTAINERS * N_VALUES); -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *container_klass = container_nodes[i]; - -      make_and_run_values_inside_container (container_klass, 1); -    } - -  start_next_test ("Each container containing each value with arrays as blocks %d iterations\n", -                   N_CONTAINERS * N_VALUES); -  arrays_write_fixed_in_blocks = TRUE; -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *container_klass = container_nodes[i]; - -      make_and_run_values_inside_container (container_klass, 1); -    } -  arrays_write_fixed_in_blocks = FALSE; - -  start_next_test ("Each container of same container of each value %d iterations\n", -                   N_CONTAINERS * N_VALUES); -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *container_klass = container_nodes[i]; - -      make_and_run_values_inside_container (container_klass, 2); -    } - -  start_next_test ("Each container of same container of same container of each value %d iterations\n", -                   N_CONTAINERS * N_VALUES); -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *container_klass = container_nodes[i]; - -      make_and_run_values_inside_container (container_klass, 3); -    } - -  start_next_test ("Each value,value pair inside a struct %d iterations\n", -                   N_VALUES * N_VALUES); -  { -    TestTypeNode *val1, *val2; -    TestTypeNode *node; - -    node = node_new (&struct_1_class); - -    i = 0; -    while ((val1 = value_generator (&i))) -      { -        j = 0; -        while ((val2 = value_generator (&j))) -          { -            TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; - -            node_append_child (node, val1); -            node_append_child (node, val2); - -            run_test_nodes (&node, 1); - -            _dbus_list_clear (&container->children); -            node_destroy (val2); -          } -        node_destroy (val1); -      } -    node_destroy (node); -  } - -  start_next_test ("All values in one big struct %d iteration\n", -                   1); -  { -    TestTypeNode *node; -    TestTypeNode *child; - -    node = node_new (&struct_1_class); - -    i = 0; -    while ((child = value_generator (&i))) -      node_append_child (node, child); - -    run_test_nodes (&node, 1); - -    node_destroy (node); -  } - -  start_next_test ("Each value in a large array %d iterations\n", -                   N_VALUES); -  { -    TestTypeNode *val; -    TestTypeNode *node; - -    node = node_new (&array_9_class); - -    i = 0; -    while ((val = value_generator (&i))) -      { -        TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; - -        node_append_child (node, val); - -        run_test_nodes (&node, 1); - -        _dbus_list_clear (&container->children); -        node_destroy (val); -      } - -    node_destroy (node); -  } - -  start_next_test ("Each container of each container of each value %d iterations\n", -                   N_CONTAINERS * N_CONTAINERS * N_VALUES); -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *outer_container_klass = container_nodes[i]; -      TestTypeNode *outer_container = node_new (outer_container_klass); - -      for (j = 0; j < N_CONTAINERS; j++) -        { -          TestTypeNode *child; -          const TestTypeNodeClass *inner_container_klass = container_nodes[j]; -          TestTypeNode *inner_container = node_new (inner_container_klass); - -          node_append_child (outer_container, inner_container); - -          m = 0; -          while ((child = value_generator (&m))) -            { -              node_append_child (inner_container, child); - -              run_test_nodes (&outer_container, 1); - -              _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); -              node_destroy (child); -            } -          _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); -          node_destroy (inner_container); -        } -      node_destroy (outer_container); -    } - -  start_next_test ("Each container of each container of each container of each value %d iterations\n", -                   N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES); -  for (i = 0; i < N_CONTAINERS; i++) -    { -      const TestTypeNodeClass *outer_container_klass = container_nodes[i]; -      TestTypeNode *outer_container = node_new (outer_container_klass); - -      for (j = 0; j < N_CONTAINERS; j++) -        { -          const TestTypeNodeClass *inner_container_klass = container_nodes[j]; -          TestTypeNode *inner_container = node_new (inner_container_klass); - -          node_append_child (outer_container, inner_container); - -          for (k = 0; k < N_CONTAINERS; k++) -            { -              TestTypeNode *child; -              const TestTypeNodeClass *center_container_klass = container_nodes[k]; -              TestTypeNode *center_container = node_new (center_container_klass); - -              node_append_child (inner_container, center_container); - -              m = 0; -              while ((child = value_generator (&m))) -                { -                  node_append_child (center_container, child); - -                  run_test_nodes (&outer_container, 1); - -                  _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children); -                  node_destroy (child); -                } -              _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); -              node_destroy (center_container); -            } -          _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); -          node_destroy (inner_container); -        } -      node_destroy (outer_container); -    } - -#if 0 -  /* This one takes a really long time, so comment it out for now */ -  start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n", -                   N_VALUES * N_VALUES * N_VALUES); -  { -    TestTypeNode *nodes[3]; - -    i = 0; -    while ((nodes[0] = value_generator (&i))) -      { -        j = 0; -        while ((nodes[1] = value_generator (&j))) -          { -            k = 0; -            while ((nodes[2] = value_generator (&k))) -              { -                run_test_nodes (nodes, 3); - -                node_destroy (nodes[2]); -              } -            node_destroy (nodes[1]); -          } -        node_destroy (nodes[0]); -      } -  } -#endif /* #if 0 expensive test */ - -  fprintf (stderr, "%d total iterations of recursive marshaling tests\n", -           n_iterations_completed_total); -  fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n", -           MAX_INITIAL_OFFSET); -  fprintf (stderr, "out of memory handling %s tested\n", -           TEST_OOM_HANDLING ? "was" : "was not"); -} - -dbus_bool_t -_dbus_marshal_recursive_test (void) -{ -  make_and_run_test_nodes (); - -  return TRUE; -} - -/* - * - * - *         Implementations of each type node class - * - * - * - */ -#define MAX_MULTI_COUNT 5 - - -#define SAMPLE_INT32           12345678 -#define SAMPLE_INT32_ALTERNATE 53781429 -static dbus_int32_t -int32_from_seed (int seed) -{ -  /* Generate an integer value that's predictable from seed.  We could -   * just use seed itself, but that would only ever touch one byte of -   * the int so would miss some kinds of bug. -   */ -  dbus_int32_t v; - -  v = 42; /* just to quiet compiler afaik */ -  switch (seed % 5) -    { -    case 0: -      v = SAMPLE_INT32; -      break; -    case 1: -      v = SAMPLE_INT32_ALTERNATE; -      break; -    case 2: -      v = -1; -      break; -    case 3: -      v = _DBUS_INT_MAX; -      break; -    case 4: -      v = 1; -      break; -    } - -  if (seed > 1) -    v *= seed; /* wraps around eventually, which is fine */ - -  return v; -} - -static dbus_bool_t -int32_write_value (TestTypeNode   *node, -                   DataBlock      *block, -                   DBusTypeWriter *writer, -                   int             seed) -{ -  /* also used for uint32 */ -  dbus_int32_t v; - -  v = int32_from_seed (seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v); -} - -static dbus_bool_t -int32_read_value (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  int             seed) -{ -  /* also used for uint32 */ -  dbus_int32_t v; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (dbus_int32_t*) &v); - -  _dbus_assert (v == int32_from_seed (seed)); - -  return TRUE; -} - -static dbus_bool_t -int32_set_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 DBusTypeReader *realign_root, -                 int             seed) -{ -  /* also used for uint32 */ -  dbus_int32_t v; - -  v = int32_from_seed (seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v, -                                      realign_root); -} - -static dbus_bool_t -int32_write_multi (TestTypeNode   *node, -                   DataBlock      *block, -                   DBusTypeWriter *writer, -                   int             seed, -                   int             count) -{ -  /* also used for uint32 */ -  dbus_int32_t values[MAX_MULTI_COUNT]; -  dbus_int32_t *v_ARRAY_INT32 = values; -  int i; - -  for (i = 0; i < count; ++i) -    values[i] = int32_from_seed (seed + i); - -  return _dbus_type_writer_write_fixed_multi (writer, -                                              node->klass->typecode, -                                              &v_ARRAY_INT32, count); -} - -static dbus_bool_t -int32_read_multi (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  int             seed, -                  int             count) -{ -  /* also used for uint32 */ -  dbus_int32_t *values; -  int n_elements; -  int i; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_fixed_multi (reader, -                                      &values, -                                      &n_elements); - -  if (n_elements != count) -    _dbus_warn ("got %d elements expected %d\n", n_elements, count); -  _dbus_assert (n_elements == count); - -  for (i = 0; i < count; i++) -    _dbus_assert (_dbus_unpack_int32 (reader->byte_order, -                                      (const unsigned char*)values + (i * 4)) == -                  int32_from_seed (seed + i)); - -  return TRUE; -} - -#ifdef DBUS_HAVE_INT64 -static dbus_int64_t -int64_from_seed (int seed) -{ -  dbus_int32_t v32; -  dbus_int64_t v; - -  v32 = int32_from_seed (seed); - -  v = - (dbus_int32_t) ~ v32; -  v |= (((dbus_int64_t)v32) << 32); - -  return v; -} -#endif - -static dbus_bool_t -int64_write_value (TestTypeNode   *node, -                   DataBlock      *block, -                   DBusTypeWriter *writer, -                   int             seed) -{ -#ifdef DBUS_HAVE_INT64 -  /* also used for uint64 */ -  dbus_int64_t v; - -  v = int64_from_seed (seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v); -#else -  return TRUE; -#endif -} - -static dbus_bool_t -int64_read_value (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  int             seed) -{ -#ifdef DBUS_HAVE_INT64 -  /* also used for uint64 */ -  dbus_int64_t v; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (dbus_int64_t*) &v); - -  _dbus_assert (v == int64_from_seed (seed)); - -  return TRUE; -#else -  return TRUE; -#endif -} - -static dbus_bool_t -int64_set_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 DBusTypeReader *realign_root, -                 int             seed) -{ -#ifdef DBUS_HAVE_INT64 -  /* also used for uint64 */ -  dbus_int64_t v; - -  v = int64_from_seed (seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v, -                                      realign_root); -#else -  return TRUE; -#endif -} - -#define MAX_SAMPLE_STRING_LEN 10 -static void -string_from_seed (char *buf, -                  int   len, -                  int   seed) -{ -  int i; -  unsigned char v; - -  _dbus_assert (len < MAX_SAMPLE_STRING_LEN); - -  /* vary the length slightly, though we also have multiple string -   * value types for this, varying it here tests the set_value code -   */ -  switch (seed % 3) -    { -    case 1: -      len += 2; -      break; -    case 2: -      len -= 2; -      break; -    } -  if (len < 0) -    len = 0; - -  v = (unsigned char) ('A' + seed); - -  i = 0; -  while (i < len) -    { -      if (v < 'A' || v > 'z') -        v = 'A'; - -      buf[i] = v; - -      v += 1; -      ++i; -    } - -  buf[i] = '\0'; -} - -static dbus_bool_t -string_write_value (TestTypeNode   *node, -                    DataBlock      *block, -                    DBusTypeWriter *writer, -                    int             seed) -{ -  char buf[MAX_SAMPLE_STRING_LEN]; -  const char *v_string = buf; - -  string_from_seed (buf, node->klass->subclass_detail, -                    seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v_string); -} - -static dbus_bool_t -string_read_value (TestTypeNode   *node, -                   DBusTypeReader *reader, -                   int             seed) -{ -  const char *v; -  char buf[MAX_SAMPLE_STRING_LEN]; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (const char **) &v); - -  string_from_seed (buf, node->klass->subclass_detail, -                    seed); - -  if (strcmp (buf, v) != 0) -    { -      _dbus_warn ("read string '%s' expected '%s'\n", -                  v, buf); -      _dbus_assert_not_reached ("test failed"); -    } - -  return TRUE; -} - -static dbus_bool_t -string_set_value (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  DBusTypeReader *realign_root, -                  int             seed) -{ -  char buf[MAX_SAMPLE_STRING_LEN]; -  const char *v_string = buf; - -  string_from_seed (buf, node->klass->subclass_detail, -                    seed); - -#if RECURSIVE_MARSHAL_WRITE_TRACE - { -   const char *old; -   _dbus_type_reader_read_basic (reader, &old); -   _dbus_verbose ("SETTING new string '%s' len %d in place of '%s' len %d\n", -                  v_string, strlen (v_string), old, strlen (old)); - } -#endif - -  return _dbus_type_reader_set_basic (reader, -                                      &v_string, -                                      realign_root); -} - -#define BOOL_FROM_SEED(seed) (seed % 2) - -static dbus_bool_t -bool_write_value (TestTypeNode   *node, -                  DataBlock      *block, -                  DBusTypeWriter *writer, -                  int             seed) -{ -  unsigned char v; - -  v = BOOL_FROM_SEED (seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v); -} - -static dbus_bool_t -bool_read_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 int             seed) -{ -  unsigned char v; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (unsigned char*) &v); - -  _dbus_assert (v == BOOL_FROM_SEED (seed)); - -  return TRUE; -} - -static dbus_bool_t -bool_set_value (TestTypeNode   *node, -                DBusTypeReader *reader, -                DBusTypeReader *realign_root, -                int             seed) -{ -  unsigned char v; - -  v = BOOL_FROM_SEED (seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v, -                                      realign_root); -} - -#define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed)) - -static dbus_bool_t -byte_write_value (TestTypeNode   *node, -                  DataBlock      *block, -                  DBusTypeWriter *writer, -                  int             seed) -{ -  unsigned char v; - -  v = BYTE_FROM_SEED (seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v); -} - -static dbus_bool_t -byte_read_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 int             seed) -{ -  unsigned char v; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (unsigned char*) &v); - -  _dbus_assert (v == BYTE_FROM_SEED (seed)); - -  return TRUE; -} - - -static dbus_bool_t -byte_set_value (TestTypeNode   *node, -                DBusTypeReader *reader, -                DBusTypeReader *realign_root, -                int             seed) -{ -  unsigned char v; - -  v = BYTE_FROM_SEED (seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v, -                                      realign_root); -} - -static double -double_from_seed (int seed) -{ -  return SAMPLE_INT32 * (double) seed + 0.3; -} - -static dbus_bool_t -double_write_value (TestTypeNode   *node, -                    DataBlock      *block, -                    DBusTypeWriter *writer, -                    int             seed) -{ -  double v; - -  v = double_from_seed (seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v); -} - -static dbus_bool_t -double_read_value (TestTypeNode   *node, -                   DBusTypeReader *reader, -                   int             seed) -{ -  double v; -  double expected; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (double*) &v); - -  expected = double_from_seed (seed); - -  if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected)) -    { -#ifdef DBUS_HAVE_INT64 -      _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n", -                  expected, v, -                  *(dbus_uint64_t*)(char*)&expected, -                  *(dbus_uint64_t*)(char*)&v); -#endif -      _dbus_assert_not_reached ("test failed"); -    } - -  return TRUE; -} - -static dbus_bool_t -double_set_value (TestTypeNode   *node, -                DBusTypeReader *reader, -                DBusTypeReader *realign_root, -                int             seed) -{ -  double v; - -  v = double_from_seed (seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v, -                                      realign_root); -} - -#define MAX_SAMPLE_OBJECT_PATH_LEN 10 -static void -object_path_from_seed (char *buf, -                       int   seed) -{ -  int i; -  unsigned char v; -  int len; - -  len = seed % 9; -  _dbus_assert (len < MAX_SAMPLE_OBJECT_PATH_LEN); - -  v = (unsigned char) ('A' + seed); - -  i = 0; -  while (i + 1 < len) -    { -      if (v < 'A' || v > 'z') -        v = 'A'; - -      buf[i] = '/'; -      ++i; -      buf[i] = v; -      ++i; - -      v += 1; -    } - -  buf[i] = '\0'; -} - -static dbus_bool_t -object_path_write_value (TestTypeNode   *node, -                         DataBlock      *block, -                         DBusTypeWriter *writer, -                         int             seed) -{ -  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; -  const char *v_string = buf; - -  object_path_from_seed (buf, seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v_string); -} - -static dbus_bool_t -object_path_read_value (TestTypeNode   *node, -                        DBusTypeReader *reader, -                        int             seed) -{ -  const char *v; -  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (const char **) &v); - -  object_path_from_seed (buf, seed); - -  if (strcmp (buf, v) != 0) -    { -      _dbus_warn ("read object path '%s' expected '%s'\n", -                  v, buf); -      _dbus_assert_not_reached ("test failed"); -    } - -  return TRUE; -} - -static dbus_bool_t -object_path_set_value (TestTypeNode   *node, -                       DBusTypeReader *reader, -                       DBusTypeReader *realign_root, -                       int             seed) -{ -  char buf[MAX_SAMPLE_OBJECT_PATH_LEN]; -  const char *v_string = buf; - -  object_path_from_seed (buf, seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v_string, -                                      realign_root); -} - -#define MAX_SAMPLE_SIGNATURE_LEN 10 -static void -signature_from_seed (char *buf, -                     int   seed) -{ -  int i; -  const char *s; -  /* try to avoid ascending, descending, or alternating length to help find bugs */ -  const char *sample_signatures[] = { -    "asax" -    "", -    "asau(xxxx)", -    "x", -    "ai", -    "a(ii)" -  }; - -  s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)]; - -  for (i = 0; s[i]; i++) -    { -      buf[i] = s[i]; -    } -  buf[i] = '\0'; -} - -static dbus_bool_t -signature_write_value (TestTypeNode   *node, -                       DataBlock      *block, -                       DBusTypeWriter *writer, -                       int             seed) -{ -  char buf[MAX_SAMPLE_SIGNATURE_LEN]; -  const char *v_string = buf; - -  signature_from_seed (buf, seed); - -  return _dbus_type_writer_write_basic (writer, -                                        node->klass->typecode, -                                        &v_string); -} - -static dbus_bool_t -signature_read_value (TestTypeNode   *node, -                      DBusTypeReader *reader, -                      int             seed) -{ -  const char *v; -  char buf[MAX_SAMPLE_SIGNATURE_LEN]; - -  check_expected_type (reader, node->klass->typecode); - -  _dbus_type_reader_read_basic (reader, -                                (const char **) &v); - -  signature_from_seed (buf, seed); - -  if (strcmp (buf, v) != 0) -    { -      _dbus_warn ("read signature value '%s' expected '%s'\n", -                  v, buf); -      _dbus_assert_not_reached ("test failed"); -    } - -  return TRUE; -} - - -static dbus_bool_t -signature_set_value (TestTypeNode   *node, -                     DBusTypeReader *reader, -                     DBusTypeReader *realign_root, -                     int             seed) -{ -  char buf[MAX_SAMPLE_SIGNATURE_LEN]; -  const char *v_string = buf; - -  signature_from_seed (buf, seed); - -  return _dbus_type_reader_set_basic (reader, -                                      &v_string, -                                      realign_root); -} - -static dbus_bool_t -struct_write_value (TestTypeNode   *node, -                    DataBlock      *block, -                    DBusTypeWriter *writer, -                    int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DataBlockState saved; -  DBusTypeWriter sub; -  int i; -  int n_copies; - -  n_copies = node->klass->subclass_detail; - -  _dbus_assert (container->children != NULL); - -  data_block_save (block, &saved); - -  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, -                                  NULL, 0, -                                  &sub)) -    return FALSE; - -  i = 0; -  while (i < n_copies) -    { -      DBusList *link; - -      link = _dbus_list_get_first_link (&container->children); -      while (link != NULL) -        { -          TestTypeNode *child = link->data; -          DBusList *next = _dbus_list_get_next_link (&container->children, link); - -          if (!node_write_value (child, block, &sub, seed + i)) -            { -              data_block_restore (block, &saved); -              return FALSE; -            } - -          link = next; -        } - -      ++i; -    } - -  if (!_dbus_type_writer_unrecurse (writer, &sub)) -    { -      data_block_restore (block, &saved); -      return FALSE; -    } - -  return TRUE; -} - -static dbus_bool_t -struct_read_or_set_value (TestTypeNode   *node, -                          DBusTypeReader *reader, -                          DBusTypeReader *realign_root, -                          int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DBusTypeReader sub; -  int i; -  int n_copies; - -  n_copies = node->klass->subclass_detail; - -  check_expected_type (reader, DBUS_TYPE_STRUCT); - -  _dbus_type_reader_recurse (reader, &sub); - -  i = 0; -  while (i < n_copies) -    { -      DBusList *link; - -      link = _dbus_list_get_first_link (&container->children); -      while (link != NULL) -        { -          TestTypeNode *child = link->data; -          DBusList *next = _dbus_list_get_next_link (&container->children, link); - -          if (realign_root == NULL) -            { -              if (!node_read_value (child, &sub, seed + i)) -                return FALSE; -            } -          else -            { -              if (!node_set_value (child, &sub, realign_root, seed + i)) -                return FALSE; -            } - -          if (i == (n_copies - 1) && next == NULL) -            NEXT_EXPECTING_FALSE (&sub); -          else -            NEXT_EXPECTING_TRUE (&sub); - -          link = next; -        } - -      ++i; -    } - -  return TRUE; -} - -static dbus_bool_t -struct_read_value (TestTypeNode   *node, -                   DBusTypeReader *reader, -                   int             seed) -{ -  return struct_read_or_set_value (node, reader, NULL, seed); -} - -static dbus_bool_t -struct_set_value (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  DBusTypeReader *realign_root, -                  int             seed) -{ -  return struct_read_or_set_value (node, reader, realign_root, seed); -} - -static dbus_bool_t -struct_build_signature (TestTypeNode   *node, -                        DBusString     *str) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  int i; -  int orig_len; -  int n_copies; - -  n_copies = node->klass->subclass_detail; - -  orig_len = _dbus_string_get_length (str); - -  if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR)) -    goto oom; - -  i = 0; -  while (i < n_copies) -    { -      DBusList *link; - -      link = _dbus_list_get_first_link (&container->children); -      while (link != NULL) -        { -          TestTypeNode *child = link->data; -          DBusList *next = _dbus_list_get_next_link (&container->children, link); - -          if (!node_build_signature (child, str)) -            goto oom; - -          link = next; -        } - -      ++i; -    } - -  if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR)) -    goto oom; - -  return TRUE; - - oom: -  _dbus_string_set_length (str, orig_len); -  return FALSE; -} - -static dbus_bool_t -array_write_value (TestTypeNode   *node, -                   DataBlock      *block, -                   DBusTypeWriter *writer, -                   int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DataBlockState saved; -  DBusTypeWriter sub; -  DBusString element_signature; -  int i; -  int n_copies; -  int element_type; -  TestTypeNode *child; - -  n_copies = node->klass->subclass_detail; - -  _dbus_assert (container->children != NULL); - -  data_block_save (block, &saved); - -  if (!_dbus_string_init (&element_signature)) -    return FALSE; - -  child = _dbus_list_get_first (&container->children); - -  if (!node_build_signature (child, -                             &element_signature)) -    goto oom; - -  element_type = first_type_in_signature (&element_signature, 0); - -  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, -                                  &element_signature, 0, -                                  &sub)) -    goto oom; - -  if (arrays_write_fixed_in_blocks && -      _dbus_type_is_fixed (element_type) && -      child->klass->write_multi) -    { -      if (!node_write_multi (child, block, &sub, seed, n_copies)) -        goto oom; -    } -  else -    { -      i = 0; -      while (i < n_copies) -        { -          DBusList *link; - -          link = _dbus_list_get_first_link (&container->children); -          while (link != NULL) -            { -              TestTypeNode *child = link->data; -              DBusList *next = _dbus_list_get_next_link (&container->children, link); - -              if (!node_write_value (child, block, &sub, seed + i)) -                goto oom; - -              link = next; -            } - -          ++i; -        } -    } - -  if (!_dbus_type_writer_unrecurse (writer, &sub)) -    goto oom; - -  _dbus_string_free (&element_signature); -  return TRUE; - - oom: -  data_block_restore (block, &saved); -  _dbus_string_free (&element_signature); -  return FALSE; -} - -static dbus_bool_t -array_read_or_set_value (TestTypeNode   *node, -                         DBusTypeReader *reader, -                         DBusTypeReader *realign_root, -                         int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DBusTypeReader sub; -  int i; -  int n_copies; -  TestTypeNode *child; - -  n_copies = node->klass->subclass_detail; - -  check_expected_type (reader, DBUS_TYPE_ARRAY); - -  child = _dbus_list_get_first (&container->children); - -  if (n_copies > 0) -    { -      _dbus_type_reader_recurse (reader, &sub); - -      if (realign_root == NULL && arrays_write_fixed_in_blocks && -          _dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && -          child->klass->read_multi) -        { -          if (!node_read_multi (child, &sub, seed, n_copies)) -            return FALSE; -        } -      else -        { -          i = 0; -          while (i < n_copies) -            { -              DBusList *link; - -              link = _dbus_list_get_first_link (&container->children); -              while (link != NULL) -                { -                  TestTypeNode *child = link->data; -                  DBusList *next = _dbus_list_get_next_link (&container->children, link); - -                  _dbus_assert (child->klass->typecode == -                                _dbus_type_reader_get_element_type (reader)); - -                  if (realign_root == NULL) -                    { -                      if (!node_read_value (child, &sub, seed + i)) -                        return FALSE; -                    } -                  else -                    { -                      if (!node_set_value (child, &sub, realign_root, seed + i)) -                        return FALSE; -                    } - -                  if (i == (n_copies - 1) && next == NULL) -                    NEXT_EXPECTING_FALSE (&sub); -                  else -                    NEXT_EXPECTING_TRUE (&sub); - -                  link = next; -                } - -              ++i; -            } -        } -    } - -  return TRUE; -} - -static dbus_bool_t -array_read_value (TestTypeNode   *node, -                  DBusTypeReader *reader, -                  int             seed) -{ -  return array_read_or_set_value (node, reader, NULL, seed); -} - -static dbus_bool_t -array_set_value (TestTypeNode   *node, -                 DBusTypeReader *reader, -                 DBusTypeReader *realign_root, -                 int             seed) -{ -  return array_read_or_set_value (node, reader, realign_root, seed); -} - -static dbus_bool_t -array_build_signature (TestTypeNode   *node, -                       DBusString     *str) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  int orig_len; - -  orig_len = _dbus_string_get_length (str); - -  if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) -    goto oom; - -  if (!node_build_signature (_dbus_list_get_first (&container->children), -                             str)) -    goto oom; - -  return TRUE; - - oom: -  _dbus_string_set_length (str, orig_len); -  return FALSE; -} - - /* 10 is random just to add another seed that we use in the suite */ -#define VARIANT_SEED 10 - -static dbus_bool_t -variant_write_value (TestTypeNode   *node, -                     DataBlock      *block, -                     DBusTypeWriter *writer, -                     int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DataBlockState saved; -  DBusTypeWriter sub; -  DBusString content_signature; -  TestTypeNode *child; - -  _dbus_assert (container->children != NULL); -  _dbus_assert (_dbus_list_length_is_one (&container->children)); - -  child = _dbus_list_get_first (&container->children); - -  data_block_save (block, &saved); - -  if (!_dbus_string_init (&content_signature)) -    return FALSE; - -  if (!node_build_signature (child, -                             &content_signature)) -    goto oom; - -  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT, -                                  &content_signature, 0, -                                  &sub)) -    goto oom; - -  if (!node_write_value (child, block, &sub, seed + VARIANT_SEED)) -    goto oom; - -  if (!_dbus_type_writer_unrecurse (writer, &sub)) -    goto oom; - -  _dbus_string_free (&content_signature); -  return TRUE; - - oom: -  data_block_restore (block, &saved); -  _dbus_string_free (&content_signature); -  return FALSE; -} - -static dbus_bool_t -variant_read_or_set_value (TestTypeNode   *node, -                           DBusTypeReader *reader, -                           DBusTypeReader *realign_root, -                           int             seed) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DBusTypeReader sub; -  TestTypeNode *child; - -  _dbus_assert (container->children != NULL); -  _dbus_assert (_dbus_list_length_is_one (&container->children)); - -  child = _dbus_list_get_first (&container->children); - -  check_expected_type (reader, DBUS_TYPE_VARIANT); - -  _dbus_type_reader_recurse (reader, &sub); - -  if (realign_root == NULL) -    { -      if (!node_read_value (child, &sub, seed + VARIANT_SEED)) -        return FALSE; -    } -  else -    { -      if (!node_set_value (child, &sub, realign_root, seed + VARIANT_SEED)) -        return FALSE; -    } - -  NEXT_EXPECTING_FALSE (&sub); - -  return TRUE; -} - -static dbus_bool_t -variant_read_value (TestTypeNode   *node, -                    DBusTypeReader *reader, -                    int             seed) -{ -  return variant_read_or_set_value (node, reader, NULL, seed); -} - -static dbus_bool_t -variant_set_value (TestTypeNode   *node, -                   DBusTypeReader *reader, -                   DBusTypeReader *realign_root, -                   int             seed) -{ -  return variant_read_or_set_value (node, reader, realign_root, seed); -} - -static void -container_destroy (TestTypeNode *node) -{ -  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; -  DBusList *link; - -  link = _dbus_list_get_first_link (&container->children); -  while (link != NULL) -    { -      TestTypeNode *child = link->data; -      DBusList *next = _dbus_list_get_next_link (&container->children, link); - -      node_destroy (child); - -      _dbus_list_free_link (link); - -      link = next; -    } -} - -#endif /* DBUS_BUILD_TESTS */ +/* tests in dbus-marshal-recursive-util.c */ diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index b5b7564e..58718f6d 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -335,6 +335,115 @@ append_string_field (DBusString *dest,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS +/** + * Parses a basic type defined by type contained in a DBusString. The + * end_return parameter may be #NULL if you aren't interested in it. The + * type is parsed and stored in value_return. Return parameters are not + * initialized if the function returns #FALSE. + * + * @param str the string + * @param type the type of the basic type + * @param start the byte index of the start of the type + * @param value_return return location of the value or #NULL + * @param end_return return location of the end of the type, or #NULL + * @returns #TRUE on success + */ +static dbus_bool_t +_dbus_string_parse_basic_type (const DBusString  *str, +			       char               type, +			       int                start, +			       void              *value, +			       int               *end_return) +{ +  int end = start; + +  switch (type) +    { +    case DBUS_TYPE_BOOLEAN: +      { +	int len = _dbus_string_get_length (str) - start; +	if (len >= 5 && _dbus_string_find_to (str, start, start + 5, "false", NULL)) +	  { +	    end += 5; +	    *(unsigned char *) value = TRUE; +	  } +	else if (len >= 4 && _dbus_string_find_to (str, start, start + 4, "true", NULL)) +	  { +	    end += 4; +	    *(unsigned char *) value = FALSE; +	  } +	else +	  _dbus_warn ("could not parse BOOLEAN\n"); +	break; +      } +    case DBUS_TYPE_BYTE: +      { +	long val = 0; + +	if (_dbus_string_get_byte (str, start) == '\'' && +	    _dbus_string_get_length (str) >= start + 4 && +	    _dbus_string_get_byte (str, start + 1) == '\\' && +	    _dbus_string_get_byte (str, start + 2) == '\'' && +	    _dbus_string_get_byte (str, start + 3) == '\'') +	  { +	    val = '\''; +	    end += 4; +	  } +	else if (_dbus_string_get_byte (str, start) == '\'' && +		 _dbus_string_get_length (str) >= start + 3 && +		 _dbus_string_get_byte (str, start + 2) == '\'') +	  { +	    val = _dbus_string_get_byte (str, start + 1); +	    end += 3; +	  } +	else +	  { +	    if (!_dbus_string_parse_int (str, start, &val, &end))  +	      _dbus_warn ("Failed to parse integer for BYTE\n"); +	  } + +	if (val > 255) +	  _dbus_warn ("A byte must be in range 0-255 not %ld\n", val); + +	*(unsigned char *) value = val; +	break; +      } +    case DBUS_TYPE_INT32: +      { +	long val; +	if (_dbus_string_parse_int (str, start, &val, &end)) +	  *(dbus_int32_t *)value = val; +	break; +      } +    case DBUS_TYPE_UINT32: +      { +	unsigned long val; +	if (_dbus_string_parse_uint (str, start, &val, &end)) +	  *(dbus_uint32_t *)value = val; +	break; +      } +#ifdef DBUS_HAVE_INT64 +    case DBUS_TYPE_INT64: +    case DBUS_TYPE_UINT64:  +      /* use stroll oull */ +      _dbus_assert_not_reached ("string -> [u]int64 not supported yet"); +      break; +#endif /* DBUS_HAVE_INT64 */ +    case DBUS_TYPE_DOUBLE: +      _dbus_string_parse_double (str, start, value, &end); +      break; +    default: +      _dbus_assert_not_reached ("not a basic type"); +      break; +    } +  if (end_return) +    *end_return = end; + +  return end != start; +} +#endif /* DBUS_BUILD_TESTS */ +  static dbus_bool_t  parse_basic_type (DBusString *src, char type,  		  DBusString *dest, dbus_bool_t *unalign, diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index f03e13f6..86064d3d 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -71,4 +71,4 @@ long               _dbus_message_loader_get_max_message_size  (DBusMessageLoader  DBUS_END_DECLS -#endif /* DBUS_MESSAGE_H */ +#endif /* DBUS_MESSAGE_INTERNAL_H */ diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h new file mode 100644 index 00000000..60b0daea --- /dev/null +++ b/dbus/dbus-message-private.h @@ -0,0 +1,119 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-message-private.h header shared between dbus-message.c and dbus-message-util.c + * + * Copyright (C) 2005  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 + * + */ +#ifndef DBUS_MESSAGE_PRIVATE_H +#define DBUS_MESSAGE_PRIVATE_H + +#include <dbus/dbus-message.h> +#include <dbus/dbus-message-internal.h> +#include <dbus/dbus-string.h> +#include <dbus/dbus-dataslot.h> +#include <dbus/dbus-marshal-header.h> + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusMessageInternals + * @{ + */ + +/** + * @typedef DBusMessageLoader + * + * The DBusMessageLoader object encapsulates the process of converting + * a byte stream into a series of DBusMessage. It buffers the incoming + * bytes as efficiently as possible, and generates a queue of + * messages. DBusMessageLoader is typically used as part of a + * DBusTransport implementation. The DBusTransport then hands off + * the loaded messages to a DBusConnection, making the messages + * visible to the application. + * + * @todo write tests for break-loader that a) randomly delete header + * fields and b) set string fields to zero-length and other funky + * values. + * + */ + +/** + * Implementation details of DBusMessageLoader. + * All members are private. + */ +struct DBusMessageLoader +{ +  int refcount;        /**< Reference count. */ + +  DBusString data;     /**< Buffered data */ + +  DBusList *messages;  /**< Complete messages. */ + +  long max_message_size; /**< Maximum size of a message */ + +  unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */ + +  unsigned int corrupted : 1; /**< We got broken data, and are no longer working */ +}; + + +/** How many bits are in the changed_stamp used to validate iterators */ +#define CHANGED_STAMP_BITS 21 + +/** + * @brief Internals of DBusMessage + * + * Object representing a message received from or to be sent to + * another application. This is an opaque object, all members + * are private. + */ +struct DBusMessage +{ +  DBusAtomic refcount; /**< Reference count */ + +  DBusHeader header; /**< Header network data and associated cache */ + +  DBusString body;   /**< Body network data. */ + +  char byte_order; /**< Message byte order. */ + +  unsigned int locked : 1; /**< Message being sent, no modifications allowed. */ + +  DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */ +  long size_counter_delta;   /**< Size we incremented the size counters by.   */ + +  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */ + +  DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */ + +#ifndef DBUS_DISABLE_CHECKS +  int generation; /**< _dbus_current_generation when message was created */ +#endif +}; + +dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter, +                                                DBusError       *error, +                                                int              first_arg_type, +                                                va_list          var_args); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_MESSAGE_H */ diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c new file mode 100644 index 00000000..47370702 --- /dev/null +++ b/dbus/dbus-message-util.c @@ -0,0 +1,1309 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests + * + * Copyright (C) 2002, 2003, 2004, 2005  Red Hat Inc. + * Copyright (C) 2002, 2003  CodeFactory AB + * + * 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-internals.h" +#include "dbus-test.h" +#include "dbus-message-private.h" +#include "dbus-marshal-recursive.h" +#include "dbus-string.h" + +/** + * @addtogroup DBusMessage + * @{ + */ + +#ifdef DBUS_BUILD_TESTS +/** + * Reads arguments from a message iterator given a variable argument + * list. Only arguments of basic type and arrays of fixed-length + * basic type may be read with this function. See + * dbus_message_get_args() for more details. + * + * @todo this is static for now because there's no corresponding + * iter_append_args() and I'm not sure we need this function to be + * public since dbus_message_get_args() is what you usually want + * + * @param iter the message iterator + * @param error error to be filled in on failure + * @param first_arg_type the first argument type + * @param ... location for first argument value, then list of type-location pairs + * @returns #FALSE if the error was set + */ +static dbus_bool_t +dbus_message_iter_get_args (DBusMessageIter *iter, +			    DBusError       *error, +			    int              first_arg_type, +			    ...) +{ +  dbus_bool_t retval; +  va_list var_args; + +  _dbus_return_val_if_fail (iter != NULL, FALSE); +  _dbus_return_val_if_error_is_set (error, FALSE); + +  va_start (var_args, first_arg_type); +  retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); +  va_end (var_args); + +  return retval; +} +#endif /* DBUS_BUILD_TESTS */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include <stdio.h> +#include <stdlib.h> + +static dbus_bool_t +check_have_valid_message (DBusMessageLoader *loader) +{ +  DBusMessage *message; +  dbus_bool_t retval; + +  message = NULL; +  retval = FALSE; + +  if (!_dbus_message_loader_queue_messages (loader)) +    _dbus_assert_not_reached ("no memory to queue messages"); + +  if (_dbus_message_loader_get_is_corrupted (loader)) +    { +      _dbus_warn ("loader corrupted on message that was expected to be valid\n"); +      goto failed; +    } + +  message = _dbus_message_loader_pop_message (loader); +  if (message == NULL) +    { +      _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n"); +      goto failed; +    } + +  if (_dbus_string_get_length (&loader->data) > 0) +    { +      _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n"); +      goto failed; +    } + +#if 0 +  /* FIXME */ +  /* Verify that we're able to properly deal with the message. +   * For example, this would detect improper handling of messages +   * in nonstandard byte order. +   */ +  if (!check_message_handling (message)) +    goto failed; +#endif + +  retval = TRUE; + + failed: +  if (message) +    dbus_message_unref (message); + +  return retval; +} + +static dbus_bool_t +check_invalid_message (DBusMessageLoader *loader) +{ +  dbus_bool_t retval; + +  retval = FALSE; + +  if (!_dbus_message_loader_queue_messages (loader)) +    _dbus_assert_not_reached ("no memory to queue messages"); + +  if (!_dbus_message_loader_get_is_corrupted (loader)) +    { +      _dbus_warn ("loader not corrupted on message that was expected to be invalid\n"); +      goto failed; +    } + +  retval = TRUE; + + failed: +  return retval; +} + +static dbus_bool_t +check_incomplete_message (DBusMessageLoader *loader) +{ +  DBusMessage *message; +  dbus_bool_t retval; + +  message = NULL; +  retval = FALSE; + +  if (!_dbus_message_loader_queue_messages (loader)) +    _dbus_assert_not_reached ("no memory to queue messages"); + +  if (_dbus_message_loader_get_is_corrupted (loader)) +    { +      _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n"); +      goto failed; +    } + +  message = _dbus_message_loader_pop_message (loader); +  if (message != NULL) +    { +      _dbus_warn ("loaded message that was expected to be incomplete\n"); +      goto failed; +    } + +  retval = TRUE; + + failed: +  if (message) +    dbus_message_unref (message); +  return retval; +} + +static dbus_bool_t +check_loader_results (DBusMessageLoader      *loader, +                      DBusMessageValidity     validity) +{ +  if (!_dbus_message_loader_queue_messages (loader)) +    _dbus_assert_not_reached ("no memory to queue messages"); + +  switch (validity) +    { +    case _DBUS_MESSAGE_VALID: +      return check_have_valid_message (loader); +    case _DBUS_MESSAGE_INVALID: +      return check_invalid_message (loader); +    case _DBUS_MESSAGE_INCOMPLETE: +      return check_incomplete_message (loader); +    case _DBUS_MESSAGE_UNKNOWN: +      return TRUE; +    } + +  _dbus_assert_not_reached ("bad DBusMessageValidity"); +  return FALSE; +} + + +/** + * Loads the message in the given message file. + * + * @param filename filename to load + * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language + * @param data string to load message into + * @returns #TRUE if the message was loaded + */ +dbus_bool_t +dbus_internal_do_not_use_load_message_file (const DBusString    *filename, +                                            dbus_bool_t          is_raw, +                                            DBusString          *data) +{ +  dbus_bool_t retval; + +  retval = FALSE; + +  if (is_raw) +    { +      DBusError error; + +      _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); +      dbus_error_init (&error); +      if (!_dbus_file_get_contents (data, filename, &error)) +        { +          _dbus_warn ("Could not load message file %s: %s\n", +                      _dbus_string_get_const_data (filename), +                      error.message); +          dbus_error_free (&error); +          goto failed; +        } +    } +  else +    { +      if (FALSE) /* Message builder disabled, probably permanently, +                  * I want to do it another way +                  */ +        { +          _dbus_warn ("Could not load message file %s\n", +                      _dbus_string_get_const_data (filename)); +          goto failed; +        } +    } + +  retval = TRUE; + + failed: + +  return retval; +} + +/** + * Tries loading the message in the given message file + * and verifies that DBusMessageLoader can handle it. + * + * @param filename filename to load + * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_file (const DBusString    *filename, +                                           dbus_bool_t          is_raw, +                                           DBusMessageValidity  expected_validity) +{ +  DBusString data; +  dbus_bool_t retval; + +  retval = FALSE; + +  if (!_dbus_string_init (&data)) +    _dbus_assert_not_reached ("could not allocate string\n"); + +  if (!dbus_internal_do_not_use_load_message_file (filename, is_raw, +                                                   &data)) +    goto failed; + +  retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); + + failed: + +  if (!retval) +    { +      if (_dbus_string_get_length (&data) > 0) +        _dbus_verbose_bytes_of_string (&data, 0, +                                       _dbus_string_get_length (&data)); + +      _dbus_warn ("Failed message loader test on %s\n", +                  _dbus_string_get_const_data (filename)); +    } + +  _dbus_string_free (&data); + +  return retval; +} + +/** + * Tries loading the given message data. + * + * + * @param data the message data + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_data (const DBusString    *data, +                                           DBusMessageValidity  expected_validity) +{ +  DBusMessageLoader *loader; +  dbus_bool_t retval; +  int len; +  int i; + +  loader = NULL; +  retval = FALSE; + +  /* Write the data one byte at a time */ + +  loader = _dbus_message_loader_new (); + +  /* check some trivial loader functions */ +  _dbus_message_loader_ref (loader); +  _dbus_message_loader_unref (loader); +  _dbus_message_loader_get_max_message_size (loader); + +  len = _dbus_string_get_length (data); +  for (i = 0; i < len; i++) +    { +      DBusString *buffer; + +      _dbus_message_loader_get_buffer (loader, &buffer); +      _dbus_string_append_byte (buffer, +                                _dbus_string_get_byte (data, i)); +      _dbus_message_loader_return_buffer (loader, buffer, 1); +    } + +  if (!check_loader_results (loader, expected_validity)) +    goto failed; + +  _dbus_message_loader_unref (loader); +  loader = NULL; + +  /* Write the data all at once */ + +  loader = _dbus_message_loader_new (); + +  { +    DBusString *buffer; + +    _dbus_message_loader_get_buffer (loader, &buffer); +    _dbus_string_copy (data, 0, buffer, +                       _dbus_string_get_length (buffer)); +    _dbus_message_loader_return_buffer (loader, buffer, 1); +  } + +  if (!check_loader_results (loader, expected_validity)) +    goto failed; + +  _dbus_message_loader_unref (loader); +  loader = NULL; + +  /* Write the data 2 bytes at a time */ + +  loader = _dbus_message_loader_new (); + +  len = _dbus_string_get_length (data); +  for (i = 0; i < len; i += 2) +    { +      DBusString *buffer; + +      _dbus_message_loader_get_buffer (loader, &buffer); +      _dbus_string_append_byte (buffer, +                                _dbus_string_get_byte (data, i)); +      if ((i+1) < len) +        _dbus_string_append_byte (buffer, +                                  _dbus_string_get_byte (data, i+1)); +      _dbus_message_loader_return_buffer (loader, buffer, 1); +    } + +  if (!check_loader_results (loader, expected_validity)) +    goto failed; + +  _dbus_message_loader_unref (loader); +  loader = NULL; + +  retval = TRUE; + + failed: + +  if (loader) +    _dbus_message_loader_unref (loader); + +  return retval; +} + +static dbus_bool_t +process_test_subdir (const DBusString          *test_base_dir, +                     const char                *subdir, +                     DBusMessageValidity        validity, +                     DBusForeachMessageFileFunc function, +                     void                      *user_data) +{ +  DBusString test_directory; +  DBusString filename; +  DBusDirIter *dir; +  dbus_bool_t retval; +  DBusError error; + +  retval = FALSE; +  dir = NULL; + +  if (!_dbus_string_init (&test_directory)) +    _dbus_assert_not_reached ("didn't allocate test_directory\n"); + +  _dbus_string_init_const (&filename, subdir); + +  if (!_dbus_string_copy (test_base_dir, 0, +                          &test_directory, 0)) +    _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + +  if (!_dbus_concat_dir_and_file (&test_directory, &filename)) +    _dbus_assert_not_reached ("couldn't allocate full path"); + +  _dbus_string_free (&filename); +  if (!_dbus_string_init (&filename)) +    _dbus_assert_not_reached ("didn't allocate filename string\n"); + +  dbus_error_init (&error); +  dir = _dbus_directory_open (&test_directory, &error); +  if (dir == NULL) +    { +      _dbus_warn ("Could not open %s: %s\n", +                  _dbus_string_get_const_data (&test_directory), +                  error.message); +      dbus_error_free (&error); +      goto failed; +    } + +  printf ("Testing %s:\n", subdir); + + next: +  while (_dbus_directory_get_next_file (dir, &filename, &error)) +    { +      DBusString full_path; +      dbus_bool_t is_raw; + +      if (!_dbus_string_init (&full_path)) +        _dbus_assert_not_reached ("couldn't init string"); + +      if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) +        _dbus_assert_not_reached ("couldn't copy dir to full_path"); + +      if (!_dbus_concat_dir_and_file (&full_path, &filename)) +        _dbus_assert_not_reached ("couldn't concat file to dir"); + +      if (_dbus_string_ends_with_c_str (&filename, ".message")) +        is_raw = FALSE; +      else if (_dbus_string_ends_with_c_str (&filename, ".message-raw")) +        is_raw = TRUE; +      else +        { +          _dbus_verbose ("Skipping non-.message file %s\n", +                         _dbus_string_get_const_data (&filename)); +	  _dbus_string_free (&full_path); +          goto next; +        } + +      printf ("    %s\n", +              _dbus_string_get_const_data (&filename)); + +      _dbus_verbose (" expecting %s for %s\n", +                     validity == _DBUS_MESSAGE_VALID ? "valid" : +                     (validity == _DBUS_MESSAGE_INVALID ? "invalid" : +                      (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")), +                     _dbus_string_get_const_data (&filename)); + +      if (! (*function) (&full_path, is_raw, validity, user_data)) +        { +          _dbus_string_free (&full_path); +          goto failed; +        } +      else +        _dbus_string_free (&full_path); +    } + +  if (dbus_error_is_set (&error)) +    { +      _dbus_warn ("Could not get next file in %s: %s\n", +                  _dbus_string_get_const_data (&test_directory), +                  error.message); +      dbus_error_free (&error); +      goto failed; +    } + +  retval = TRUE; + + failed: + +  if (dir) +    _dbus_directory_close (dir); +  _dbus_string_free (&test_directory); +  _dbus_string_free (&filename); + +  return retval; +} + +/** + * Runs the given function on every message file in the test suite. + * The function should return #FALSE on test failure or fatal error. + * + * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data) + * @param func the function to run + * @param user_data data for function + * @returns #FALSE if there's a failure + */ +dbus_bool_t +dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir, +                                               DBusForeachMessageFileFunc func, +                                               void                      *user_data) +{ +  DBusString test_directory; +  dbus_bool_t retval; + +  retval = FALSE; + +  _dbus_string_init_const (&test_directory, test_data_dir); + +  if (!process_test_subdir (&test_directory, "valid-messages", +                            _DBUS_MESSAGE_VALID, func, user_data)) +    goto failed; + +  if (!process_test_subdir (&test_directory, "invalid-messages", +                            _DBUS_MESSAGE_INVALID, func, user_data)) +    goto failed; + +  if (!process_test_subdir (&test_directory, "incomplete-messages", +                            _DBUS_MESSAGE_INCOMPLETE, func, user_data)) +    goto failed; + +  retval = TRUE; + + failed: + +  _dbus_string_free (&test_directory); + +  return retval; +} + +#define GET_AND_CHECK(iter, typename, literal)                                  \ +  do {                                                                          \ +    if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \ +      _dbus_assert_not_reached ("got wrong argument type from message iter");   \ +    dbus_message_iter_get_basic (&iter, &v_##typename);                         \ +    if (v_##typename != literal)                                                \ +      _dbus_assert_not_reached ("got wrong value from message iter");           \ +  } while (0) + +#define GET_AND_CHECK_STRCMP(iter, typename, literal)                           \ +  do {                                                                          \ +    if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \ +      _dbus_assert_not_reached ("got wrong argument type from message iter");   \ +    dbus_message_iter_get_basic (&iter, &v_##typename);                         \ +    if (strcmp (v_##typename, literal) != 0)                                    \ +      _dbus_assert_not_reached ("got wrong value from message iter");           \ +  } while (0) + +#define GET_AND_CHECK_AND_NEXT(iter, typename, literal)         \ +  do {                                                          \ +    GET_AND_CHECK(iter, typename, literal);                     \ +    if (!dbus_message_iter_next (&iter))                        \ +      _dbus_assert_not_reached ("failed to move iter to next"); \ +  } while (0) + +#define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal)  \ +  do {                                                          \ +    GET_AND_CHECK_STRCMP(iter, typename, literal);              \ +    if (!dbus_message_iter_next (&iter))                        \ +      _dbus_assert_not_reached ("failed to move iter to next"); \ +  } while (0) + +static void +message_iter_test (DBusMessage *message) +{ +  DBusMessageIter iter, array, array2; +  const char *v_STRING; +  double v_DOUBLE; +  dbus_int32_t v_INT32; +  dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 +  dbus_int64_t v_INT64; +  dbus_uint64_t v_UINT64; +#endif +  unsigned char v_BYTE; +  unsigned char v_BOOLEAN; + +  const dbus_int32_t *our_int_array; +  int len; + +  dbus_message_iter_init (message, &iter); + +  GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string"); +  GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678); +  GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e); +  GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159); + +  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) +    _dbus_assert_not_reached ("Argument type not an array"); + +  if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE) +    _dbus_assert_not_reached ("Array type not double"); + +  dbus_message_iter_recurse (&iter, &array); + +  GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5); +  GET_AND_CHECK (array, DOUBLE, 2.5); + +  if (dbus_message_iter_next (&array)) +    _dbus_assert_not_reached ("Didn't reach end of array"); + +  if (!dbus_message_iter_next (&iter)) +    _dbus_assert_not_reached ("Reached end of arguments"); + +  GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0); + +  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) +    _dbus_assert_not_reached ("no array"); + +  if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32) +    _dbus_assert_not_reached ("Array type not int32"); + +  /* Empty array */ +  dbus_message_iter_recurse (&iter, &array); + +  if (dbus_message_iter_next (&array)) +    _dbus_assert_not_reached ("Didn't reach end of array"); + +  if (!dbus_message_iter_next (&iter)) +    _dbus_assert_not_reached ("Reached end of arguments"); + +  GET_AND_CHECK (iter, BYTE, 0xF0); + +  if (dbus_message_iter_next (&iter)) +    _dbus_assert_not_reached ("Didn't reach end of arguments"); +} + +static void +verify_test_message (DBusMessage *message) +{ +  DBusMessageIter iter; +  DBusError error; +  dbus_int32_t our_int; +  const char *our_str; +  double our_double; +  unsigned char our_bool; +  unsigned char our_byte_1, our_byte_2; +  dbus_uint32_t our_uint32; +  const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef; +  int our_uint32_array_len; +  dbus_int32_t *our_int32_array = (void*)0xdeadbeef; +  int our_int32_array_len; +#ifdef DBUS_HAVE_INT64 +  dbus_int64_t our_int64; +  dbus_uint64_t our_uint64; +  dbus_int64_t *our_uint64_array = (void*)0xdeadbeef; +  int our_uint64_array_len; +  const dbus_int64_t *our_int64_array = (void*)0xdeadbeef; +  int our_int64_array_len; +#endif +  const double *our_double_array = (void*)0xdeadbeef; +  int our_double_array_len; +  const unsigned char *our_byte_array = (void*)0xdeadbeef; +  int our_byte_array_len; +  const unsigned char *our_boolean_array = (void*)0xdeadbeef; +  int our_boolean_array_len; + +  dbus_message_iter_init (message, &iter); + +  dbus_error_init (&error); +  if (!dbus_message_iter_get_args (&iter, &error, +				   DBUS_TYPE_INT32, &our_int, +#ifdef DBUS_HAVE_INT64 +                                   DBUS_TYPE_INT64, &our_int64, +                                   DBUS_TYPE_UINT64, &our_uint64, +#endif +				   DBUS_TYPE_STRING, &our_str, +				   DBUS_TYPE_DOUBLE, &our_double, +				   DBUS_TYPE_BOOLEAN, &our_bool, +				   DBUS_TYPE_BYTE, &our_byte_1, +				   DBUS_TYPE_BYTE, &our_byte_2, +				   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, +                                   &our_uint32_array, &our_uint32_array_len, +                                   DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, +                                   &our_int32_array, &our_int32_array_len, +#ifdef DBUS_HAVE_INT64 +				   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, +                                   &our_uint64_array, &our_uint64_array_len, +                                   DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, +                                   &our_int64_array, &our_int64_array_len, +#endif +                                   DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, +                                   &our_double_array, &our_double_array_len, +                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, +                                   &our_byte_array, &our_byte_array_len, +                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, +                                   &our_boolean_array, &our_boolean_array_len, +				   0)) +    { +      _dbus_warn ("error: %s - %s\n", error.name, +                  (error.message != NULL) ? error.message : "no message"); +      _dbus_assert_not_reached ("Could not get arguments"); +    } + +  if (our_int != -0x12345678) +    _dbus_assert_not_reached ("integers differ!"); + +#ifdef DBUS_HAVE_INT64 +  if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd)) +    _dbus_assert_not_reached ("64-bit integers differ!"); +  if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd)) +    _dbus_assert_not_reached ("64-bit unsigned integers differ!"); +#endif + +  if (our_double != 3.14159) +    _dbus_assert_not_reached ("doubles differ!"); + +  if (strcmp (our_str, "Test string") != 0) +    _dbus_assert_not_reached ("strings differ!"); + +  if (!our_bool) +    _dbus_assert_not_reached ("booleans differ"); + +  if (our_byte_1 != 42) +    _dbus_assert_not_reached ("bytes differ!"); + +  if (our_byte_2 != 24) +    _dbus_assert_not_reached ("bytes differ!"); + +  if (our_uint32_array_len != 4 || +      our_uint32_array[0] != 0x12345678 || +      our_uint32_array[1] != 0x23456781 || +      our_uint32_array[2] != 0x34567812 || +      our_uint32_array[3] != 0x45678123) +    _dbus_assert_not_reached ("uint array differs"); + +  if (our_int32_array_len != 4 || +      our_int32_array[0] != 0x12345678 || +      our_int32_array[1] != -0x23456781 || +      our_int32_array[2] != 0x34567812 || +      our_int32_array[3] != -0x45678123) +    _dbus_assert_not_reached ("int array differs"); + +#ifdef DBUS_HAVE_INT64 +  if (our_uint64_array_len != 4 || +      our_uint64_array[0] != 0x12345678 || +      our_uint64_array[1] != 0x23456781 || +      our_uint64_array[2] != 0x34567812 || +      our_uint64_array[3] != 0x45678123) +    _dbus_assert_not_reached ("uint64 array differs"); + +  if (our_int64_array_len != 4 || +      our_int64_array[0] != 0x12345678 || +      our_int64_array[1] != -0x23456781 || +      our_int64_array[2] != 0x34567812 || +      our_int64_array[3] != -0x45678123) +    _dbus_assert_not_reached ("int64 array differs"); +#endif /* DBUS_HAVE_INT64 */ + +  if (our_double_array_len != 3) +    _dbus_assert_not_reached ("double array had wrong length"); + +  /* On all IEEE machines (i.e. everything sane) exact equality +   * should be preserved over the wire +   */ +  if (our_double_array[0] != 0.1234 || +      our_double_array[1] != 9876.54321 || +      our_double_array[2] != -300.0) +    _dbus_assert_not_reached ("double array had wrong values"); + +  if (our_byte_array_len != 4) +    _dbus_assert_not_reached ("byte array had wrong length"); + +  if (our_byte_array[0] != 'a' || +      our_byte_array[1] != 'b' || +      our_byte_array[2] != 'c' || +      our_byte_array[3] != 234) +    _dbus_assert_not_reached ("byte array had wrong values"); + +  if (our_boolean_array_len != 5) +    _dbus_assert_not_reached ("bool array had wrong length"); + +  if (our_boolean_array[0] != TRUE || +      our_boolean_array[1] != FALSE || +      our_boolean_array[2] != TRUE || +      our_boolean_array[3] != TRUE || +      our_boolean_array[4] != FALSE) +    _dbus_assert_not_reached ("bool array had wrong values"); + +  if (dbus_message_iter_next (&iter)) +    _dbus_assert_not_reached ("Didn't reach end of arguments"); +} + +/** + * @ingroup DBusMessageInternals + * Unit test for DBusMessage. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_message_test (const char *test_data_dir) +{ +  DBusMessage *message; +  DBusMessageLoader *loader; +  DBusMessageIter iter, child_iter, child_iter2, child_iter3; +  int i; +  const char *data; +  DBusMessage *copy; +  const char *name1; +  const char *name2; +  const dbus_uint32_t our_uint32_array[] = +    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; +  const dbus_uint32_t our_int32_array[] = +    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; +  const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; +  const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; +#ifdef DBUS_HAVE_INT64 +  const dbus_uint64_t our_uint64_array[] = +    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; +  const dbus_uint64_t our_int64_array[] = +    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; +  const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; +  const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; +#endif +  const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" }; +  const char **v_ARRAY_STRING = our_string_array; +  const double our_double_array[] = { 0.1234, 9876.54321, -300.0 }; +  const double *v_ARRAY_DOUBLE = our_double_array; +  const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 }; +  const unsigned char *v_ARRAY_BYTE = our_byte_array; +  const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE }; +  const unsigned char *v_ARRAY_BOOLEAN = our_boolean_array; +  char sig[64]; +  const char *s; +  char *t; +  DBusError error; +  const char *v_STRING; +  double v_DOUBLE; +  dbus_int32_t v_INT32; +  dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 +  dbus_int64_t v_INT64; +  dbus_uint64_t v_UINT64; +#endif +  unsigned char v_BYTE; +  unsigned char v2_BYTE; +  unsigned char v_BOOLEAN; + +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod"); +  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); +  _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", +                                             "TestMethod")); +  _dbus_assert (strcmp (dbus_message_get_path (message), +                        "/org/freedesktop/TestPath") == 0); +  _dbus_message_set_serial (message, 1234); + +  /* string length including nul byte not a multiple of 4 */ +  if (!dbus_message_set_sender (message, "org.foo.bar1")) +    _dbus_assert_not_reached ("out of memory"); + +  _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); +  dbus_message_set_reply_serial (message, 5678); + +  _dbus_verbose_bytes_of_string (&message->header.data, 0, +                                 _dbus_string_get_length (&message->header.data)); +  _dbus_verbose_bytes_of_string (&message->body, 0, +                                 _dbus_string_get_length (&message->body)); + +  if (!dbus_message_set_sender (message, NULL)) +    _dbus_assert_not_reached ("out of memory"); + + +  _dbus_verbose_bytes_of_string (&message->header.data, 0, +                                 _dbus_string_get_length (&message->header.data)); +  _dbus_verbose_bytes_of_string (&message->body, 0, +                                 _dbus_string_get_length (&message->body)); + + +  _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); +  _dbus_assert (dbus_message_get_serial (message) == 1234); +  _dbus_assert (dbus_message_get_reply_serial (message) == 5678); +  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + +  _dbus_assert (dbus_message_get_no_reply (message) == FALSE); +  dbus_message_set_no_reply (message, TRUE); +  _dbus_assert (dbus_message_get_no_reply (message) == TRUE); +  dbus_message_set_no_reply (message, FALSE); +  _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + +  /* Set/get some header fields */ + +  if (!dbus_message_set_path (message, "/foo")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_path (message), +                        "/foo") == 0); + +  if (!dbus_message_set_interface (message, "org.Foo")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_interface (message), +                        "org.Foo") == 0); + +  if (!dbus_message_set_member (message, "Bar")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_member (message), +                        "Bar") == 0); + +  /* Set/get them with longer values */ +  if (!dbus_message_set_path (message, "/foo/bar")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_path (message), +                        "/foo/bar") == 0); + +  if (!dbus_message_set_interface (message, "org.Foo.Bar")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_interface (message), +                        "org.Foo.Bar") == 0); + +  if (!dbus_message_set_member (message, "BarFoo")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_member (message), +                        "BarFoo") == 0); + +  /* Realloc shorter again */ + +  if (!dbus_message_set_path (message, "/foo")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_path (message), +                        "/foo") == 0); + +  if (!dbus_message_set_interface (message, "org.Foo")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_interface (message), +                        "org.Foo") == 0); + +  if (!dbus_message_set_member (message, "Bar")) +    _dbus_assert_not_reached ("out of memory"); +  _dbus_assert (strcmp (dbus_message_get_member (message), +                        "Bar") == 0); + +  dbus_message_unref (message); + +  /* Test the vararg functions */ +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod"); +  _dbus_message_set_serial (message, 1); + +  v_INT32 = -0x12345678; +#ifdef DBUS_HAVE_INT64 +  v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd); +  v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd); +#endif +  v_STRING = "Test string"; +  v_DOUBLE = 3.14159; +  v_BOOLEAN = TRUE; +  v_BYTE = 42; +  v2_BYTE = 24; + +  dbus_message_append_args (message, +			    DBUS_TYPE_INT32, &v_INT32, +#ifdef DBUS_HAVE_INT64 +                            DBUS_TYPE_INT64, &v_INT64, +                            DBUS_TYPE_UINT64, &v_UINT64, +#endif +			    DBUS_TYPE_STRING, &v_STRING, +			    DBUS_TYPE_DOUBLE, &v_DOUBLE, +			    DBUS_TYPE_BOOLEAN, &v_BOOLEAN, +			    DBUS_TYPE_BYTE, &v_BYTE, +			    DBUS_TYPE_BYTE, &v2_BYTE, +			    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32, +                            _DBUS_N_ELEMENTS (our_uint32_array), +                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32, +                            _DBUS_N_ELEMENTS (our_int32_array), +#ifdef DBUS_HAVE_INT64 +                            DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64, +                            _DBUS_N_ELEMENTS (our_uint64_array), +                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64, +                            _DBUS_N_ELEMENTS (our_int64_array), +#endif +                            DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE, +                            _DBUS_N_ELEMENTS (our_double_array), +                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE, +                            _DBUS_N_ELEMENTS (our_byte_array), +                            DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, +                            _DBUS_N_ELEMENTS (our_boolean_array), +			    DBUS_TYPE_INVALID); + +  i = 0; +  sig[i++] = DBUS_TYPE_INT32; +#ifdef DBUS_HAVE_INT64 +  sig[i++] = DBUS_TYPE_INT64; +  sig[i++] = DBUS_TYPE_UINT64; +#endif +  sig[i++] = DBUS_TYPE_STRING; +  sig[i++] = DBUS_TYPE_DOUBLE; +  sig[i++] = DBUS_TYPE_BOOLEAN; +  sig[i++] = DBUS_TYPE_BYTE; +  sig[i++] = DBUS_TYPE_BYTE; +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_UINT32; +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_INT32; +#ifdef DBUS_HAVE_INT64 +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_UINT64; +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_INT64; +#endif +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_DOUBLE; +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_BYTE; +  sig[i++] = DBUS_TYPE_ARRAY; +  sig[i++] = DBUS_TYPE_BOOLEAN; +  sig[i++] = DBUS_TYPE_INVALID; + +  _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); + +  _dbus_verbose ("HEADER\n"); +  _dbus_verbose_bytes_of_string (&message->header.data, 0, +                                 _dbus_string_get_length (&message->header.data)); +  _dbus_verbose ("BODY\n"); +  _dbus_verbose_bytes_of_string (&message->body, 0, +                                 _dbus_string_get_length (&message->body)); + +  _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n", +                 sig, dbus_message_get_signature (message)); + +  s = dbus_message_get_signature (message); + +  _dbus_assert (dbus_message_has_signature (message, sig)); +  _dbus_assert (strcmp (s, sig) == 0); + +  verify_test_message (message); + +  copy = dbus_message_copy (message); + +  _dbus_assert (dbus_message_get_reply_serial (message) == +                dbus_message_get_reply_serial (copy)); +  _dbus_assert (message->header.padding == copy->header.padding); + +  _dbus_assert (_dbus_string_get_length (&message->header.data) == +                _dbus_string_get_length (©->header.data)); + +  _dbus_assert (_dbus_string_get_length (&message->body) == +                _dbus_string_get_length (©->body)); + +  verify_test_message (copy); + +  name1 = dbus_message_get_interface (message); +  name2 = dbus_message_get_interface (copy); + +  _dbus_assert (strcmp (name1, name2) == 0); + +  name1 = dbus_message_get_member (message); +  name2 = dbus_message_get_member (copy); + +  _dbus_assert (strcmp (name1, name2) == 0); + +  dbus_message_unref (message); +  dbus_message_unref (copy); + +#if 0 +  /* FIXME */ +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod"); + +  _dbus_message_set_serial (message, 1); +  dbus_message_set_reply_serial (message, 0x12345678); + +  dbus_message_iter_init_append (message, &iter); +  dbus_message_iter_append_string (&iter, "Test string"); +  dbus_message_iter_append_int32 (&iter, -0x12345678); +  dbus_message_iter_append_uint32 (&iter, 0xedd1e); +  dbus_message_iter_append_double (&iter, 3.14159); + +  dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE); +  dbus_message_iter_append_double (&child_iter, 1.5); +  dbus_message_iter_append_double (&child_iter, 2.5); + +  /* dict */ +  dbus_message_iter_append_dict (&iter, &child_iter); +  dbus_message_iter_append_dict_key (&child_iter, "test"); +  dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF); + +  /* dict (in dict) */ +  dbus_message_iter_append_dict_key (&child_iter, "testdict"); +  dbus_message_iter_append_dict (&child_iter, &child_iter2); + +  dbus_message_iter_append_dict_key (&child_iter2, "dictkey"); +  dbus_message_iter_append_string (&child_iter2, "dictvalue"); + +  /* array of array of int32  (in dict) */ +  dbus_message_iter_append_dict_key (&child_iter, "array"); +  dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY); +  dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); +  dbus_message_iter_append_int32 (&child_iter3, 0x12345678); +  dbus_message_iter_append_int32 (&child_iter3, 0x23456781); +  _dbus_warn ("next call expected to fail with wrong array type\n"); +  _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32)); +  dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); +  dbus_message_iter_append_int32 (&child_iter3, 0x34567812); +  dbus_message_iter_append_int32 (&child_iter3, 0x45678123); +  dbus_message_iter_append_int32 (&child_iter3, 0x56781234); + +  dbus_message_iter_append_byte (&iter, 0xF0); + +  dbus_message_iter_append_nil (&iter); + +  dbus_message_iter_append_custom (&iter, "MyTypeName", +                                   "data", 5); + +  dbus_message_iter_append_byte (&iter, 0xF0); + +  dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_INT32); + +  dbus_message_iter_append_byte (&iter, 0xF0); + +  dbus_message_iter_append_dict (&iter, &child_iter); + +  dbus_message_iter_append_byte (&iter, 0xF0); + +  message_iter_test (message); + +  /* Message loader test */ +  _dbus_message_lock (message); +  loader = _dbus_message_loader_new (); + +  /* check ref/unref */ +  _dbus_message_loader_ref (loader); +  _dbus_message_loader_unref (loader); + +  /* Write the header data one byte at a time */ +  data = _dbus_string_get_const_data (&message->header); +  for (i = 0; i < _dbus_string_get_length (&message->header); i++) +    { +      DBusString *buffer; + +      _dbus_message_loader_get_buffer (loader, &buffer); +      _dbus_string_append_byte (buffer, data[i]); +      _dbus_message_loader_return_buffer (loader, buffer, 1); +    } + +  /* Write the body data one byte at a time */ +  data = _dbus_string_get_const_data (&message->body); +  for (i = 0; i < _dbus_string_get_length (&message->body); i++) +    { +      DBusString *buffer; + +      _dbus_message_loader_get_buffer (loader, &buffer); +      _dbus_string_append_byte (buffer, data[i]); +      _dbus_message_loader_return_buffer (loader, buffer, 1); +    } + +  copy = dbus_message_copy (message); /* save for tests below */ +  dbus_message_unref (message); + +  /* Now pop back the message */ +  if (!_dbus_message_loader_queue_messages (loader)) +    _dbus_assert_not_reached ("no memory to queue messages"); + +  if (_dbus_message_loader_get_is_corrupted (loader)) +    _dbus_assert_not_reached ("message loader corrupted"); + +  message = _dbus_message_loader_pop_message (loader); +  if (!message) +    _dbus_assert_not_reached ("received a NULL message"); + +  if (dbus_message_get_reply_serial (message) != 0x12345678) +    _dbus_assert_not_reached ("reply serial fields differ"); + +  message_iter_test (message); + +  dbus_message_unref (message); +  _dbus_message_loader_unref (loader); + +  message = dbus_message_new_method_return (copy); +  if (message == NULL) +    _dbus_assert_not_reached ("out of memory\n"); +  dbus_message_unref (copy); + +  if (!dbus_message_append_args (message, +                                 DBUS_TYPE_STRING, "hello", +                                 DBUS_TYPE_INVALID)) +    _dbus_assert_not_reached ("no memory"); + +  if (!dbus_message_has_signature (message, "s")) +    _dbus_assert_not_reached ("method return has wrong signature"); + +  dbus_error_init (&error); +  if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, +                              &t, DBUS_TYPE_INVALID)) + +    { +      _dbus_warn ("Failed to get expected string arg: %s\n", error.message); +      exit (1); +    } +  dbus_free (t); + +  dbus_message_unref (message); + +  /* This ServiceAcquired message used to trigger a bug in +   * setting header fields, adding to regression test. +   */ +  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                     "ServiceAcquired"); + +  if (message == NULL) +    _dbus_assert_not_reached ("out of memory"); + +  _dbus_verbose ("Bytes after creation\n"); +  _dbus_verbose_bytes_of_string (&message->header, 0, +                                 _dbus_string_get_length (&message->header)); + +  if (!dbus_message_set_destination (message, ":1.0") || +      !dbus_message_append_args (message, +                                 DBUS_TYPE_STRING, ":1.0", +                                 DBUS_TYPE_INVALID)) +    _dbus_assert_not_reached ("out of memory"); + +  _dbus_verbose ("Bytes after set_destination() and append_args()\n"); +  _dbus_verbose_bytes_of_string (&message->header, 0, +                                 _dbus_string_get_length (&message->header)); + +  if (!dbus_message_set_sender (message, "org.freedesktop.DBus")) +    _dbus_assert_not_reached ("out of memory"); + +  _dbus_verbose ("Bytes after set_sender()\n"); +  _dbus_verbose_bytes_of_string (&message->header, 0, +                                 _dbus_string_get_length (&message->header)); + +  /* When the bug happened the above set_destination() would +   * corrupt the signature +   */ +  if (!dbus_message_has_signature (message, "s")) +    { +      _dbus_warn ("Signature should be 's' but is '%s'\n", +                  dbus_message_get_signature (message)); +      _dbus_assert_not_reached ("signal has wrong signature"); +    } + +  /* have to set destination again to reproduce the bug */ +  if (!dbus_message_set_destination (message, ":1.0")) +    _dbus_assert_not_reached ("out of memory"); + +  _dbus_verbose ("Bytes after set_destination()\n"); +  _dbus_verbose_bytes_of_string (&message->header, 0, +                                 _dbus_string_get_length (&message->header)); + +  /* When the bug happened the above set_destination() would +   * corrupt the signature +   */ +  if (!dbus_message_has_signature (message, "s")) +    { +      _dbus_warn ("Signature should be 's' but is '%s'\n", +                  dbus_message_get_signature (message)); +      _dbus_assert_not_reached ("signal has wrong signature"); +    } + +  dbus_error_init (&error); +  if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, +                              &t, DBUS_TYPE_INVALID)) + +    { +      _dbus_warn ("Failed to get expected string arg for signal: %s\n", error.message); +      exit (1); +    } +  dbus_free (t); + +  dbus_message_unref (message); + +  /* Now load every message in test_data_dir if we have one */ +  if (test_data_dir == NULL) +    return TRUE; + +  return dbus_internal_do_not_use_foreach_message_file (test_data_dir, +                                                        (DBusForeachMessageFileFunc) +                                                        dbus_internal_do_not_use_try_message_file, +                                                        NULL); + +#endif /* Commented out most tests for now */ + +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index fc83a07e..8bb48667 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -26,12 +26,10 @@  #include "dbus-marshal-recursive.h"  #include "dbus-marshal-validate.h"  #include "dbus-marshal-header.h" -#include "dbus-message.h" -#include "dbus-message-internal.h" +#include "dbus-message-private.h"  #include "dbus-object-tree.h"  #include "dbus-memory.h"  #include "dbus-list.h" -#include "dbus-dataslot.h"  #include <string.h>  /** @@ -44,54 +42,11 @@   * @{   */ -static dbus_bool_t dbus_message_iter_get_args        (DBusMessageIter *iter, -                                                      DBusError       *error, -                                                      int              first_arg_type, -                                                      ...); -static dbus_bool_t dbus_message_iter_get_args_valist (DBusMessageIter *iter, -                                                      DBusError       *error, -                                                      int              first_arg_type, -                                                      va_list          var_args); -  /* Not thread locked, but strictly const/read-only so should be OK   */  /** An static string representing an empty signature */  _DBUS_STRING_DEFINE_STATIC(_dbus_empty_signature_str,  ""); -/** How many bits are in the changed_stamp used to validate iterators */ -#define CHANGED_STAMP_BITS 21 - -/** - * @brief Internals of DBusMessage - * - * Object representing a message received from or to be sent to - * another application. This is an opaque object, all members - * are private. - */ -struct DBusMessage -{ -  DBusAtomic refcount; /**< Reference count */ - -  DBusHeader header; /**< Header network data and associated cache */ - -  DBusString body;   /**< Body network data. */ - -  char byte_order; /**< Message byte order. */ - -  unsigned int locked : 1; /**< Message being sent, no modifications allowed. */ - -  DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */ -  long size_counter_delta;   /**< Size we incremented the size counters by.   */ - -  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */ - -  DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */ - -#ifndef DBUS_DISABLE_CHECKS -  int generation; /**< _dbus_current_generation when message was created */ -#endif -}; -  /* these have wacky values to help trap uninitialized iterators;   * but has to fit in 3 bits   */ @@ -1380,42 +1335,7 @@ dbus_message_get_args_valist (DBusMessage     *message,    _dbus_return_val_if_error_is_set (error, FALSE);    dbus_message_iter_init (message, &iter); -  return dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args); -} - -/** - * Reads arguments from a message iterator given a variable argument - * list. Only arguments of basic type and arrays of fixed-length - * basic type may be read with this function. See - * dbus_message_get_args() for more details. - * - * @todo this is static for now because there's no corresponding - * iter_append_args() and I'm not sure we need this function to be - * public since dbus_message_get_args() is what you usually want - * - * @param iter the message iterator - * @param error error to be filled in on failure - * @param first_arg_type the first argument type - * @param ... location for first argument value, then list of type-location pairs - * @returns #FALSE if the error was set - */ -static dbus_bool_t -dbus_message_iter_get_args (DBusMessageIter *iter, -			    DBusError       *error, -			    int              first_arg_type, -			    ...) -{ -  dbus_bool_t retval; -  va_list var_args; - -  _dbus_return_val_if_fail (iter != NULL, FALSE); -  _dbus_return_val_if_error_is_set (error, FALSE); - -  va_start (var_args, first_arg_type); -  retval = dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); -  va_end (var_args); - -  return retval; +  return _dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args);  }  static void @@ -1700,9 +1620,6 @@ dbus_message_iter_get_fixed_array (DBusMessageIter  *iter,   * dbus_message_get_args() is the place to go for complete   * documentation.   * - * @todo this is static for now, should be public if - * dbus_message_iter_get_args_valist() is made public. - *   * @see dbus_message_get_args   * @param iter the message iter   * @param error error to be filled in @@ -1710,18 +1627,17 @@ dbus_message_iter_get_fixed_array (DBusMessageIter  *iter,   * @param var_args return location for first argument, followed by list of type/location pairs   * @returns #FALSE if error was set   */ -static dbus_bool_t -dbus_message_iter_get_args_valist (DBusMessageIter *iter, -				   DBusError       *error, -				   int              first_arg_type, -				   va_list          var_args) +dbus_bool_t +_dbus_message_iter_get_args_valist (DBusMessageIter *iter, +                                    DBusError       *error, +                                    int              first_arg_type, +                                    va_list          var_args)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter;    int spec_type, msg_type, i;    dbus_bool_t retval; -  _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); -  _dbus_return_val_if_error_is_set (error, FALSE); +  _dbus_assert (_dbus_message_iter_check (real));    retval = FALSE; @@ -1749,7 +1665,7 @@ dbus_message_iter_get_args_valist (DBusMessageIter *iter,            ptr = va_arg (var_args, DBusBasicValue*); -          _dbus_return_val_if_fail (ptr != NULL, FALSE); +          _dbus_assert (ptr != NULL);            _dbus_type_reader_read_basic (&real->u.reader,                                          ptr); @@ -1782,8 +1698,8 @@ dbus_message_iter_get_args_valist (DBusMessageIter *iter,                ptr = va_arg (var_args, const DBusBasicValue**);                n_elements_p = va_arg (var_args, int*); -              _dbus_return_val_if_fail (ptr != NULL, FALSE); -              _dbus_return_val_if_fail (n_elements_p != NULL, FALSE); +              _dbus_assert (ptr != NULL); +              _dbus_assert (n_elements_p != NULL);                _dbus_type_reader_recurse (&real->u.reader, &array); @@ -1801,8 +1717,8 @@ dbus_message_iter_get_args_valist (DBusMessageIter *iter,                str_array_p = va_arg (var_args, char***);                n_elements_p = va_arg (var_args, int*); -              _dbus_return_val_if_fail (str_array_p != NULL, FALSE); -              _dbus_return_val_if_fail (n_elements_p != NULL, FALSE); +              _dbus_assert (str_array_p != NULL); +              _dbus_assert (n_elements_p != NULL);                /* Count elements in the array */                _dbus_type_reader_recurse (&real->u.reader, &array); @@ -2937,41 +2853,6 @@ dbus_set_error_from_message (DBusError   *error,   *   * @{   */ -/** - * @typedef DBusMessageLoader - * - * The DBusMessageLoader object encapsulates the process of converting - * a byte stream into a series of DBusMessage. It buffers the incoming - * bytes as efficiently as possible, and generates a queue of - * messages. DBusMessageLoader is typically used as part of a - * DBusTransport implementation. The DBusTransport then hands off - * the loaded messages to a DBusConnection, making the messages - * visible to the application. - * - * @todo write tests for break-loader that a) randomly delete header - * fields and b) set string fields to zero-length and other funky - * values. - * - */ - -/** - * Implementation details of DBusMessageLoader. - * All members are private. - */ -struct DBusMessageLoader -{ -  int refcount;        /**< Reference count. */ - -  DBusString data;     /**< Buffered data */ - -  DBusList *messages;  /**< Complete messages. */ - -  long max_message_size; /**< Maximum size of a message */ - -  unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */ - -  unsigned int corrupted : 1; /**< We got broken data, and are no longer working */ -};  /**   * The initial buffer size of the message loader. @@ -3579,1240 +3460,5 @@ dbus_message_type_to_string (int type)  }  /** @} */ -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include <stdio.h> -#include <stdlib.h> - -static dbus_bool_t -check_have_valid_message (DBusMessageLoader *loader) -{ -  DBusMessage *message; -  dbus_bool_t retval; - -  message = NULL; -  retval = FALSE; - -  if (!_dbus_message_loader_queue_messages (loader)) -    _dbus_assert_not_reached ("no memory to queue messages"); - -  if (_dbus_message_loader_get_is_corrupted (loader)) -    { -      _dbus_warn ("loader corrupted on message that was expected to be valid\n"); -      goto failed; -    } - -  message = _dbus_message_loader_pop_message (loader); -  if (message == NULL) -    { -      _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n"); -      goto failed; -    } - -  if (_dbus_string_get_length (&loader->data) > 0) -    { -      _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n"); -      goto failed; -    } - -#if 0 -  /* FIXME */ -  /* Verify that we're able to properly deal with the message. -   * For example, this would detect improper handling of messages -   * in nonstandard byte order. -   */ -  if (!check_message_handling (message)) -    goto failed; -#endif - -  retval = TRUE; - - failed: -  if (message) -    dbus_message_unref (message); - -  return retval; -} - -static dbus_bool_t -check_invalid_message (DBusMessageLoader *loader) -{ -  dbus_bool_t retval; - -  retval = FALSE; - -  if (!_dbus_message_loader_queue_messages (loader)) -    _dbus_assert_not_reached ("no memory to queue messages"); - -  if (!_dbus_message_loader_get_is_corrupted (loader)) -    { -      _dbus_warn ("loader not corrupted on message that was expected to be invalid\n"); -      goto failed; -    } - -  retval = TRUE; - - failed: -  return retval; -} - -static dbus_bool_t -check_incomplete_message (DBusMessageLoader *loader) -{ -  DBusMessage *message; -  dbus_bool_t retval; - -  message = NULL; -  retval = FALSE; - -  if (!_dbus_message_loader_queue_messages (loader)) -    _dbus_assert_not_reached ("no memory to queue messages"); - -  if (_dbus_message_loader_get_is_corrupted (loader)) -    { -      _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n"); -      goto failed; -    } - -  message = _dbus_message_loader_pop_message (loader); -  if (message != NULL) -    { -      _dbus_warn ("loaded message that was expected to be incomplete\n"); -      goto failed; -    } - -  retval = TRUE; - - failed: -  if (message) -    dbus_message_unref (message); -  return retval; -} - -static dbus_bool_t -check_loader_results (DBusMessageLoader      *loader, -                      DBusMessageValidity     validity) -{ -  if (!_dbus_message_loader_queue_messages (loader)) -    _dbus_assert_not_reached ("no memory to queue messages"); - -  switch (validity) -    { -    case _DBUS_MESSAGE_VALID: -      return check_have_valid_message (loader); -    case _DBUS_MESSAGE_INVALID: -      return check_invalid_message (loader); -    case _DBUS_MESSAGE_INCOMPLETE: -      return check_incomplete_message (loader); -    case _DBUS_MESSAGE_UNKNOWN: -      return TRUE; -    } - -  _dbus_assert_not_reached ("bad DBusMessageValidity"); -  return FALSE; -} - - -/** - * Loads the message in the given message file. - * - * @param filename filename to load - * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language - * @param data string to load message into - * @returns #TRUE if the message was loaded - */ -dbus_bool_t -dbus_internal_do_not_use_load_message_file (const DBusString    *filename, -                                            dbus_bool_t          is_raw, -                                            DBusString          *data) -{ -  dbus_bool_t retval; - -  retval = FALSE; - -  if (is_raw) -    { -      DBusError error; - -      _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); -      dbus_error_init (&error); -      if (!_dbus_file_get_contents (data, filename, &error)) -        { -          _dbus_warn ("Could not load message file %s: %s\n", -                      _dbus_string_get_const_data (filename), -                      error.message); -          dbus_error_free (&error); -          goto failed; -        } -    } -  else -    { -      if (FALSE) /* Message builder disabled, probably permanently, -                  * I want to do it another way -                  */ -        { -          _dbus_warn ("Could not load message file %s\n", -                      _dbus_string_get_const_data (filename)); -          goto failed; -        } -    } - -  retval = TRUE; - - failed: - -  return retval; -} - -/** - * Tries loading the message in the given message file - * and verifies that DBusMessageLoader can handle it. - * - * @param filename filename to load - * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language - * @param expected_validity what the message has to be like to return #TRUE - * @returns #TRUE if the message has the expected validity - */ -dbus_bool_t -dbus_internal_do_not_use_try_message_file (const DBusString    *filename, -                                           dbus_bool_t          is_raw, -                                           DBusMessageValidity  expected_validity) -{ -  DBusString data; -  dbus_bool_t retval; - -  retval = FALSE; - -  if (!_dbus_string_init (&data)) -    _dbus_assert_not_reached ("could not allocate string\n"); - -  if (!dbus_internal_do_not_use_load_message_file (filename, is_raw, -                                                   &data)) -    goto failed; - -  retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); - - failed: - -  if (!retval) -    { -      if (_dbus_string_get_length (&data) > 0) -        _dbus_verbose_bytes_of_string (&data, 0, -                                       _dbus_string_get_length (&data)); - -      _dbus_warn ("Failed message loader test on %s\n", -                  _dbus_string_get_const_data (filename)); -    } - -  _dbus_string_free (&data); - -  return retval; -} - -/** - * Tries loading the given message data. - * - * - * @param data the message data - * @param expected_validity what the message has to be like to return #TRUE - * @returns #TRUE if the message has the expected validity - */ -dbus_bool_t -dbus_internal_do_not_use_try_message_data (const DBusString    *data, -                                           DBusMessageValidity  expected_validity) -{ -  DBusMessageLoader *loader; -  dbus_bool_t retval; -  int len; -  int i; - -  loader = NULL; -  retval = FALSE; - -  /* Write the data one byte at a time */ - -  loader = _dbus_message_loader_new (); - -  /* check some trivial loader functions */ -  _dbus_message_loader_ref (loader); -  _dbus_message_loader_unref (loader); -  _dbus_message_loader_get_max_message_size (loader); - -  len = _dbus_string_get_length (data); -  for (i = 0; i < len; i++) -    { -      DBusString *buffer; - -      _dbus_message_loader_get_buffer (loader, &buffer); -      _dbus_string_append_byte (buffer, -                                _dbus_string_get_byte (data, i)); -      _dbus_message_loader_return_buffer (loader, buffer, 1); -    } - -  if (!check_loader_results (loader, expected_validity)) -    goto failed; - -  _dbus_message_loader_unref (loader); -  loader = NULL; - -  /* Write the data all at once */ - -  loader = _dbus_message_loader_new (); - -  { -    DBusString *buffer; - -    _dbus_message_loader_get_buffer (loader, &buffer); -    _dbus_string_copy (data, 0, buffer, -                       _dbus_string_get_length (buffer)); -    _dbus_message_loader_return_buffer (loader, buffer, 1); -  } - -  if (!check_loader_results (loader, expected_validity)) -    goto failed; - -  _dbus_message_loader_unref (loader); -  loader = NULL; - -  /* Write the data 2 bytes at a time */ - -  loader = _dbus_message_loader_new (); - -  len = _dbus_string_get_length (data); -  for (i = 0; i < len; i += 2) -    { -      DBusString *buffer; - -      _dbus_message_loader_get_buffer (loader, &buffer); -      _dbus_string_append_byte (buffer, -                                _dbus_string_get_byte (data, i)); -      if ((i+1) < len) -        _dbus_string_append_byte (buffer, -                                  _dbus_string_get_byte (data, i+1)); -      _dbus_message_loader_return_buffer (loader, buffer, 1); -    } - -  if (!check_loader_results (loader, expected_validity)) -    goto failed; - -  _dbus_message_loader_unref (loader); -  loader = NULL; - -  retval = TRUE; - - failed: - -  if (loader) -    _dbus_message_loader_unref (loader); - -  return retval; -} - -static dbus_bool_t -process_test_subdir (const DBusString          *test_base_dir, -                     const char                *subdir, -                     DBusMessageValidity        validity, -                     DBusForeachMessageFileFunc function, -                     void                      *user_data) -{ -  DBusString test_directory; -  DBusString filename; -  DBusDirIter *dir; -  dbus_bool_t retval; -  DBusError error; - -  retval = FALSE; -  dir = NULL; - -  if (!_dbus_string_init (&test_directory)) -    _dbus_assert_not_reached ("didn't allocate test_directory\n"); - -  _dbus_string_init_const (&filename, subdir); - -  if (!_dbus_string_copy (test_base_dir, 0, -                          &test_directory, 0)) -    _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); - -  if (!_dbus_concat_dir_and_file (&test_directory, &filename)) -    _dbus_assert_not_reached ("couldn't allocate full path"); - -  _dbus_string_free (&filename); -  if (!_dbus_string_init (&filename)) -    _dbus_assert_not_reached ("didn't allocate filename string\n"); - -  dbus_error_init (&error); -  dir = _dbus_directory_open (&test_directory, &error); -  if (dir == NULL) -    { -      _dbus_warn ("Could not open %s: %s\n", -                  _dbus_string_get_const_data (&test_directory), -                  error.message); -      dbus_error_free (&error); -      goto failed; -    } - -  printf ("Testing %s:\n", subdir); - - next: -  while (_dbus_directory_get_next_file (dir, &filename, &error)) -    { -      DBusString full_path; -      dbus_bool_t is_raw; - -      if (!_dbus_string_init (&full_path)) -        _dbus_assert_not_reached ("couldn't init string"); - -      if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) -        _dbus_assert_not_reached ("couldn't copy dir to full_path"); - -      if (!_dbus_concat_dir_and_file (&full_path, &filename)) -        _dbus_assert_not_reached ("couldn't concat file to dir"); - -      if (_dbus_string_ends_with_c_str (&filename, ".message")) -        is_raw = FALSE; -      else if (_dbus_string_ends_with_c_str (&filename, ".message-raw")) -        is_raw = TRUE; -      else -        { -          _dbus_verbose ("Skipping non-.message file %s\n", -                         _dbus_string_get_const_data (&filename)); -	  _dbus_string_free (&full_path); -          goto next; -        } - -      printf ("    %s\n", -              _dbus_string_get_const_data (&filename)); - -      _dbus_verbose (" expecting %s for %s\n", -                     validity == _DBUS_MESSAGE_VALID ? "valid" : -                     (validity == _DBUS_MESSAGE_INVALID ? "invalid" : -                      (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")), -                     _dbus_string_get_const_data (&filename)); - -      if (! (*function) (&full_path, is_raw, validity, user_data)) -        { -          _dbus_string_free (&full_path); -          goto failed; -        } -      else -        _dbus_string_free (&full_path); -    } - -  if (dbus_error_is_set (&error)) -    { -      _dbus_warn ("Could not get next file in %s: %s\n", -                  _dbus_string_get_const_data (&test_directory), -                  error.message); -      dbus_error_free (&error); -      goto failed; -    } - -  retval = TRUE; - - failed: - -  if (dir) -    _dbus_directory_close (dir); -  _dbus_string_free (&test_directory); -  _dbus_string_free (&filename); - -  return retval; -} - -/** - * Runs the given function on every message file in the test suite. - * The function should return #FALSE on test failure or fatal error. - * - * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data) - * @param func the function to run - * @param user_data data for function - * @returns #FALSE if there's a failure - */ -dbus_bool_t -dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir, -                                               DBusForeachMessageFileFunc func, -                                               void                      *user_data) -{ -  DBusString test_directory; -  dbus_bool_t retval; - -  retval = FALSE; - -  _dbus_string_init_const (&test_directory, test_data_dir); - -  if (!process_test_subdir (&test_directory, "valid-messages", -                            _DBUS_MESSAGE_VALID, func, user_data)) -    goto failed; - -  if (!process_test_subdir (&test_directory, "invalid-messages", -                            _DBUS_MESSAGE_INVALID, func, user_data)) -    goto failed; - -  if (!process_test_subdir (&test_directory, "incomplete-messages", -                            _DBUS_MESSAGE_INCOMPLETE, func, user_data)) -    goto failed; - -  retval = TRUE; - - failed: - -  _dbus_string_free (&test_directory); - -  return retval; -} - -#define GET_AND_CHECK(iter, typename, literal)                                  \ -  do {                                                                          \ -    if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \ -      _dbus_assert_not_reached ("got wrong argument type from message iter");   \ -    dbus_message_iter_get_basic (&iter, &v_##typename);                         \ -    if (v_##typename != literal)                                                \ -      _dbus_assert_not_reached ("got wrong value from message iter");           \ -  } while (0) - -#define GET_AND_CHECK_STRCMP(iter, typename, literal)                           \ -  do {                                                                          \ -    if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \ -      _dbus_assert_not_reached ("got wrong argument type from message iter");   \ -    dbus_message_iter_get_basic (&iter, &v_##typename);                         \ -    if (strcmp (v_##typename, literal) != 0)                                    \ -      _dbus_assert_not_reached ("got wrong value from message iter");           \ -  } while (0) - -#define GET_AND_CHECK_AND_NEXT(iter, typename, literal)         \ -  do {                                                          \ -    GET_AND_CHECK(iter, typename, literal);                     \ -    if (!dbus_message_iter_next (&iter))                        \ -      _dbus_assert_not_reached ("failed to move iter to next"); \ -  } while (0) - -#define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal)  \ -  do {                                                          \ -    GET_AND_CHECK_STRCMP(iter, typename, literal);              \ -    if (!dbus_message_iter_next (&iter))                        \ -      _dbus_assert_not_reached ("failed to move iter to next"); \ -  } while (0) - -static void -message_iter_test (DBusMessage *message) -{ -  DBusMessageIter iter, array, array2; -  const char *v_STRING; -  double v_DOUBLE; -  dbus_int32_t v_INT32; -  dbus_uint32_t v_UINT32; -#ifdef DBUS_HAVE_INT64 -  dbus_int64_t v_INT64; -  dbus_uint64_t v_UINT64; -#endif -  unsigned char v_BYTE; -  unsigned char v_BOOLEAN; - -  const dbus_int32_t *our_int_array; -  int len; - -  dbus_message_iter_init (message, &iter); - -  GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string"); -  GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678); -  GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e); -  GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159); - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("Argument type not an array"); - -  if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE) -    _dbus_assert_not_reached ("Array type not double"); - -  dbus_message_iter_recurse (&iter, &array); - -  GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5); -  GET_AND_CHECK (array, DOUBLE, 2.5); - -  if (dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Didn't reach end of array"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0); - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("no array"); - -  if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Array type not int32"); - -  /* Empty array */ -  dbus_message_iter_recurse (&iter, &array); - -  if (dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Didn't reach end of array"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  GET_AND_CHECK (iter, BYTE, 0xF0); - -  if (dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Didn't reach end of arguments"); -} - -static void -verify_test_message (DBusMessage *message) -{ -  DBusMessageIter iter; -  DBusError error; -  dbus_int32_t our_int; -  const char *our_str; -  double our_double; -  unsigned char our_bool; -  unsigned char our_byte_1, our_byte_2; -  dbus_uint32_t our_uint32; -  const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef; -  int our_uint32_array_len; -  dbus_int32_t *our_int32_array = (void*)0xdeadbeef; -  int our_int32_array_len; -#ifdef DBUS_HAVE_INT64 -  dbus_int64_t our_int64; -  dbus_uint64_t our_uint64; -  dbus_int64_t *our_uint64_array = (void*)0xdeadbeef; -  int our_uint64_array_len; -  const dbus_int64_t *our_int64_array = (void*)0xdeadbeef; -  int our_int64_array_len; -#endif -  const double *our_double_array = (void*)0xdeadbeef; -  int our_double_array_len; -  const unsigned char *our_byte_array = (void*)0xdeadbeef; -  int our_byte_array_len; -  const unsigned char *our_boolean_array = (void*)0xdeadbeef; -  int our_boolean_array_len; - -  dbus_message_iter_init (message, &iter); - -  dbus_error_init (&error); -  if (!dbus_message_iter_get_args (&iter, &error, -				   DBUS_TYPE_INT32, &our_int, -#ifdef DBUS_HAVE_INT64 -                                   DBUS_TYPE_INT64, &our_int64, -                                   DBUS_TYPE_UINT64, &our_uint64, -#endif -				   DBUS_TYPE_STRING, &our_str, -				   DBUS_TYPE_DOUBLE, &our_double, -				   DBUS_TYPE_BOOLEAN, &our_bool, -				   DBUS_TYPE_BYTE, &our_byte_1, -				   DBUS_TYPE_BYTE, &our_byte_2, -				   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, -                                   &our_uint32_array, &our_uint32_array_len, -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, -                                   &our_int32_array, &our_int32_array_len, -#ifdef DBUS_HAVE_INT64 -				   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, -                                   &our_uint64_array, &our_uint64_array_len, -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, -                                   &our_int64_array, &our_int64_array_len, -#endif -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, -                                   &our_double_array, &our_double_array_len, -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, -                                   &our_byte_array, &our_byte_array_len, -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, -                                   &our_boolean_array, &our_boolean_array_len, -				   0)) -    { -      _dbus_warn ("error: %s - %s\n", error.name, -                  (error.message != NULL) ? error.message : "no message"); -      _dbus_assert_not_reached ("Could not get arguments"); -    } - -  if (our_int != -0x12345678) -    _dbus_assert_not_reached ("integers differ!"); - -#ifdef DBUS_HAVE_INT64 -  if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd)) -    _dbus_assert_not_reached ("64-bit integers differ!"); -  if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd)) -    _dbus_assert_not_reached ("64-bit unsigned integers differ!"); -#endif - -  if (our_double != 3.14159) -    _dbus_assert_not_reached ("doubles differ!"); - -  if (strcmp (our_str, "Test string") != 0) -    _dbus_assert_not_reached ("strings differ!"); - -  if (!our_bool) -    _dbus_assert_not_reached ("booleans differ"); - -  if (our_byte_1 != 42) -    _dbus_assert_not_reached ("bytes differ!"); - -  if (our_byte_2 != 24) -    _dbus_assert_not_reached ("bytes differ!"); - -  if (our_uint32_array_len != 4 || -      our_uint32_array[0] != 0x12345678 || -      our_uint32_array[1] != 0x23456781 || -      our_uint32_array[2] != 0x34567812 || -      our_uint32_array[3] != 0x45678123) -    _dbus_assert_not_reached ("uint array differs"); - -  if (our_int32_array_len != 4 || -      our_int32_array[0] != 0x12345678 || -      our_int32_array[1] != -0x23456781 || -      our_int32_array[2] != 0x34567812 || -      our_int32_array[3] != -0x45678123) -    _dbus_assert_not_reached ("int array differs"); - -#ifdef DBUS_HAVE_INT64 -  if (our_uint64_array_len != 4 || -      our_uint64_array[0] != 0x12345678 || -      our_uint64_array[1] != 0x23456781 || -      our_uint64_array[2] != 0x34567812 || -      our_uint64_array[3] != 0x45678123) -    _dbus_assert_not_reached ("uint64 array differs"); - -  if (our_int64_array_len != 4 || -      our_int64_array[0] != 0x12345678 || -      our_int64_array[1] != -0x23456781 || -      our_int64_array[2] != 0x34567812 || -      our_int64_array[3] != -0x45678123) -    _dbus_assert_not_reached ("int64 array differs"); -#endif /* DBUS_HAVE_INT64 */ - -  if (our_double_array_len != 3) -    _dbus_assert_not_reached ("double array had wrong length"); - -  /* On all IEEE machines (i.e. everything sane) exact equality -   * should be preserved over the wire -   */ -  if (our_double_array[0] != 0.1234 || -      our_double_array[1] != 9876.54321 || -      our_double_array[2] != -300.0) -    _dbus_assert_not_reached ("double array had wrong values"); - -  if (our_byte_array_len != 4) -    _dbus_assert_not_reached ("byte array had wrong length"); - -  if (our_byte_array[0] != 'a' || -      our_byte_array[1] != 'b' || -      our_byte_array[2] != 'c' || -      our_byte_array[3] != 234) -    _dbus_assert_not_reached ("byte array had wrong values"); - -  if (our_boolean_array_len != 5) -    _dbus_assert_not_reached ("bool array had wrong length"); - -  if (our_boolean_array[0] != TRUE || -      our_boolean_array[1] != FALSE || -      our_boolean_array[2] != TRUE || -      our_boolean_array[3] != TRUE || -      our_boolean_array[4] != FALSE) -    _dbus_assert_not_reached ("bool array had wrong values"); - -  if (dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Didn't reach end of arguments"); -} - -/** - * @ingroup DBusMessageInternals - * Unit test for DBusMessage. - * - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_message_test (const char *test_data_dir) -{ -  DBusMessage *message; -  DBusMessageLoader *loader; -  DBusMessageIter iter, child_iter, child_iter2, child_iter3; -  int i; -  const char *data; -  DBusMessage *copy; -  const char *name1; -  const char *name2; -  const dbus_uint32_t our_uint32_array[] = -    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; -  const dbus_uint32_t our_int32_array[] = -    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; -  const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; -  const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; -#ifdef DBUS_HAVE_INT64 -  const dbus_uint64_t our_uint64_array[] = -    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; -  const dbus_uint64_t our_int64_array[] = -    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; -  const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; -  const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; -#endif -  const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" }; -  const char **v_ARRAY_STRING = our_string_array; -  const double our_double_array[] = { 0.1234, 9876.54321, -300.0 }; -  const double *v_ARRAY_DOUBLE = our_double_array; -  const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 }; -  const unsigned char *v_ARRAY_BYTE = our_byte_array; -  const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE }; -  const unsigned char *v_ARRAY_BOOLEAN = our_boolean_array; -  char sig[64]; -  const char *s; -  char *t; -  DBusError error; -  const char *v_STRING; -  double v_DOUBLE; -  dbus_int32_t v_INT32; -  dbus_uint32_t v_UINT32; -#ifdef DBUS_HAVE_INT64 -  dbus_int64_t v_INT64; -  dbus_uint64_t v_UINT64; -#endif -  unsigned char v_BYTE; -  unsigned char v2_BYTE; -  unsigned char v_BOOLEAN; - -  _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); - -  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", -                                          "/org/freedesktop/TestPath", -                                          "Foo.TestInterface", -                                          "TestMethod"); -  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); -  _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", -                                             "TestMethod")); -  _dbus_assert (strcmp (dbus_message_get_path (message), -                        "/org/freedesktop/TestPath") == 0); -  _dbus_message_set_serial (message, 1234); - -  /* string length including nul byte not a multiple of 4 */ -  if (!dbus_message_set_sender (message, "org.foo.bar1")) -    _dbus_assert_not_reached ("out of memory"); - -  _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); -  dbus_message_set_reply_serial (message, 5678); - -  _dbus_verbose_bytes_of_string (&message->header.data, 0, -                                 _dbus_string_get_length (&message->header.data)); -  _dbus_verbose_bytes_of_string (&message->body, 0, -                                 _dbus_string_get_length (&message->body)); - -  if (!dbus_message_set_sender (message, NULL)) -    _dbus_assert_not_reached ("out of memory"); - - -  _dbus_verbose_bytes_of_string (&message->header.data, 0, -                                 _dbus_string_get_length (&message->header.data)); -  _dbus_verbose_bytes_of_string (&message->body, 0, -                                 _dbus_string_get_length (&message->body)); - - -  _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); -  _dbus_assert (dbus_message_get_serial (message) == 1234); -  _dbus_assert (dbus_message_get_reply_serial (message) == 5678); -  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); - -  _dbus_assert (dbus_message_get_no_reply (message) == FALSE); -  dbus_message_set_no_reply (message, TRUE); -  _dbus_assert (dbus_message_get_no_reply (message) == TRUE); -  dbus_message_set_no_reply (message, FALSE); -  _dbus_assert (dbus_message_get_no_reply (message) == FALSE); - -  /* Set/get some header fields */ - -  if (!dbus_message_set_path (message, "/foo")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_path (message), -                        "/foo") == 0); - -  if (!dbus_message_set_interface (message, "org.Foo")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_interface (message), -                        "org.Foo") == 0); - -  if (!dbus_message_set_member (message, "Bar")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_member (message), -                        "Bar") == 0); - -  /* Set/get them with longer values */ -  if (!dbus_message_set_path (message, "/foo/bar")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_path (message), -                        "/foo/bar") == 0); - -  if (!dbus_message_set_interface (message, "org.Foo.Bar")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_interface (message), -                        "org.Foo.Bar") == 0); - -  if (!dbus_message_set_member (message, "BarFoo")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_member (message), -                        "BarFoo") == 0); - -  /* Realloc shorter again */ - -  if (!dbus_message_set_path (message, "/foo")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_path (message), -                        "/foo") == 0); - -  if (!dbus_message_set_interface (message, "org.Foo")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_interface (message), -                        "org.Foo") == 0); - -  if (!dbus_message_set_member (message, "Bar")) -    _dbus_assert_not_reached ("out of memory"); -  _dbus_assert (strcmp (dbus_message_get_member (message), -                        "Bar") == 0); - -  dbus_message_unref (message); - -  /* Test the vararg functions */ -  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", -                                          "/org/freedesktop/TestPath", -                                          "Foo.TestInterface", -                                          "TestMethod"); -  _dbus_message_set_serial (message, 1); - -  v_INT32 = -0x12345678; -#ifdef DBUS_HAVE_INT64 -  v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd); -  v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd); -#endif -  v_STRING = "Test string"; -  v_DOUBLE = 3.14159; -  v_BOOLEAN = TRUE; -  v_BYTE = 42; -  v2_BYTE = 24; - -  dbus_message_append_args (message, -			    DBUS_TYPE_INT32, &v_INT32, -#ifdef DBUS_HAVE_INT64 -                            DBUS_TYPE_INT64, &v_INT64, -                            DBUS_TYPE_UINT64, &v_UINT64, -#endif -			    DBUS_TYPE_STRING, &v_STRING, -			    DBUS_TYPE_DOUBLE, &v_DOUBLE, -			    DBUS_TYPE_BOOLEAN, &v_BOOLEAN, -			    DBUS_TYPE_BYTE, &v_BYTE, -			    DBUS_TYPE_BYTE, &v2_BYTE, -			    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32, -                            _DBUS_N_ELEMENTS (our_uint32_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32, -                            _DBUS_N_ELEMENTS (our_int32_array), -#ifdef DBUS_HAVE_INT64 -                            DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64, -                            _DBUS_N_ELEMENTS (our_uint64_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64, -                            _DBUS_N_ELEMENTS (our_int64_array), -#endif -                            DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE, -                            _DBUS_N_ELEMENTS (our_double_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE, -                            _DBUS_N_ELEMENTS (our_byte_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, -                            _DBUS_N_ELEMENTS (our_boolean_array), -			    DBUS_TYPE_INVALID); - -  i = 0; -  sig[i++] = DBUS_TYPE_INT32; -#ifdef DBUS_HAVE_INT64 -  sig[i++] = DBUS_TYPE_INT64; -  sig[i++] = DBUS_TYPE_UINT64; -#endif -  sig[i++] = DBUS_TYPE_STRING; -  sig[i++] = DBUS_TYPE_DOUBLE; -  sig[i++] = DBUS_TYPE_BOOLEAN; -  sig[i++] = DBUS_TYPE_BYTE; -  sig[i++] = DBUS_TYPE_BYTE; -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_UINT32; -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_INT32; -#ifdef DBUS_HAVE_INT64 -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_UINT64; -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_INT64; -#endif -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_DOUBLE; -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_BYTE; -  sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_BOOLEAN; -  sig[i++] = DBUS_TYPE_INVALID; - -  _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); - -  _dbus_verbose ("HEADER\n"); -  _dbus_verbose_bytes_of_string (&message->header.data, 0, -                                 _dbus_string_get_length (&message->header.data)); -  _dbus_verbose ("BODY\n"); -  _dbus_verbose_bytes_of_string (&message->body, 0, -                                 _dbus_string_get_length (&message->body)); - -  _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n", -                 sig, dbus_message_get_signature (message)); - -  s = dbus_message_get_signature (message); - -  _dbus_assert (dbus_message_has_signature (message, sig)); -  _dbus_assert (strcmp (s, sig) == 0); - -  verify_test_message (message); - -  copy = dbus_message_copy (message); - -  _dbus_assert (dbus_message_get_reply_serial (message) == -                dbus_message_get_reply_serial (copy)); -  _dbus_assert (message->header.padding == copy->header.padding); - -  _dbus_assert (_dbus_string_get_length (&message->header.data) == -                _dbus_string_get_length (©->header.data)); - -  _dbus_assert (_dbus_string_get_length (&message->body) == -                _dbus_string_get_length (©->body)); - -  verify_test_message (copy); - -  name1 = dbus_message_get_interface (message); -  name2 = dbus_message_get_interface (copy); - -  _dbus_assert (strcmp (name1, name2) == 0); - -  name1 = dbus_message_get_member (message); -  name2 = dbus_message_get_member (copy); - -  _dbus_assert (strcmp (name1, name2) == 0); - -  dbus_message_unref (message); -  dbus_message_unref (copy); - -#if 0 -  /* FIXME */ -  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", -                                          "/org/freedesktop/TestPath", -                                          "Foo.TestInterface", -                                          "TestMethod"); - -  _dbus_message_set_serial (message, 1); -  dbus_message_set_reply_serial (message, 0x12345678); - -  dbus_message_iter_init_append (message, &iter); -  dbus_message_iter_append_string (&iter, "Test string"); -  dbus_message_iter_append_int32 (&iter, -0x12345678); -  dbus_message_iter_append_uint32 (&iter, 0xedd1e); -  dbus_message_iter_append_double (&iter, 3.14159); - -  dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE); -  dbus_message_iter_append_double (&child_iter, 1.5); -  dbus_message_iter_append_double (&child_iter, 2.5); - -  /* dict */ -  dbus_message_iter_append_dict (&iter, &child_iter); -  dbus_message_iter_append_dict_key (&child_iter, "test"); -  dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF); - -  /* dict (in dict) */ -  dbus_message_iter_append_dict_key (&child_iter, "testdict"); -  dbus_message_iter_append_dict (&child_iter, &child_iter2); - -  dbus_message_iter_append_dict_key (&child_iter2, "dictkey"); -  dbus_message_iter_append_string (&child_iter2, "dictvalue"); - -  /* array of array of int32  (in dict) */ -  dbus_message_iter_append_dict_key (&child_iter, "array"); -  dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY); -  dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); -  dbus_message_iter_append_int32 (&child_iter3, 0x12345678); -  dbus_message_iter_append_int32 (&child_iter3, 0x23456781); -  _dbus_warn ("next call expected to fail with wrong array type\n"); -  _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32)); -  dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); -  dbus_message_iter_append_int32 (&child_iter3, 0x34567812); -  dbus_message_iter_append_int32 (&child_iter3, 0x45678123); -  dbus_message_iter_append_int32 (&child_iter3, 0x56781234); - -  dbus_message_iter_append_byte (&iter, 0xF0); - -  dbus_message_iter_append_nil (&iter); - -  dbus_message_iter_append_custom (&iter, "MyTypeName", -                                   "data", 5); - -  dbus_message_iter_append_byte (&iter, 0xF0); - -  dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_INT32); - -  dbus_message_iter_append_byte (&iter, 0xF0); - -  dbus_message_iter_append_dict (&iter, &child_iter); - -  dbus_message_iter_append_byte (&iter, 0xF0); - -  message_iter_test (message); - -  /* Message loader test */ -  _dbus_message_lock (message); -  loader = _dbus_message_loader_new (); - -  /* check ref/unref */ -  _dbus_message_loader_ref (loader); -  _dbus_message_loader_unref (loader); - -  /* Write the header data one byte at a time */ -  data = _dbus_string_get_const_data (&message->header); -  for (i = 0; i < _dbus_string_get_length (&message->header); i++) -    { -      DBusString *buffer; - -      _dbus_message_loader_get_buffer (loader, &buffer); -      _dbus_string_append_byte (buffer, data[i]); -      _dbus_message_loader_return_buffer (loader, buffer, 1); -    } - -  /* Write the body data one byte at a time */ -  data = _dbus_string_get_const_data (&message->body); -  for (i = 0; i < _dbus_string_get_length (&message->body); i++) -    { -      DBusString *buffer; - -      _dbus_message_loader_get_buffer (loader, &buffer); -      _dbus_string_append_byte (buffer, data[i]); -      _dbus_message_loader_return_buffer (loader, buffer, 1); -    } - -  copy = dbus_message_copy (message); /* save for tests below */ -  dbus_message_unref (message); - -  /* Now pop back the message */ -  if (!_dbus_message_loader_queue_messages (loader)) -    _dbus_assert_not_reached ("no memory to queue messages"); - -  if (_dbus_message_loader_get_is_corrupted (loader)) -    _dbus_assert_not_reached ("message loader corrupted"); - -  message = _dbus_message_loader_pop_message (loader); -  if (!message) -    _dbus_assert_not_reached ("received a NULL message"); - -  if (dbus_message_get_reply_serial (message) != 0x12345678) -    _dbus_assert_not_reached ("reply serial fields differ"); - -  message_iter_test (message); - -  dbus_message_unref (message); -  _dbus_message_loader_unref (loader); - -  message = dbus_message_new_method_return (copy); -  if (message == NULL) -    _dbus_assert_not_reached ("out of memory\n"); -  dbus_message_unref (copy); - -  if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, "hello", -                                 DBUS_TYPE_INVALID)) -    _dbus_assert_not_reached ("no memory"); - -  if (!dbus_message_has_signature (message, "s")) -    _dbus_assert_not_reached ("method return has wrong signature"); - -  dbus_error_init (&error); -  if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, -                              &t, DBUS_TYPE_INVALID)) - -    { -      _dbus_warn ("Failed to get expected string arg: %s\n", error.message); -      exit (1); -    } -  dbus_free (t); - -  dbus_message_unref (message); - -  /* This ServiceAcquired message used to trigger a bug in -   * setting header fields, adding to regression test. -   */ -  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, -                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                     "ServiceAcquired"); - -  if (message == NULL) -    _dbus_assert_not_reached ("out of memory"); - -  _dbus_verbose ("Bytes after creation\n"); -  _dbus_verbose_bytes_of_string (&message->header, 0, -                                 _dbus_string_get_length (&message->header)); - -  if (!dbus_message_set_destination (message, ":1.0") || -      !dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, ":1.0", -                                 DBUS_TYPE_INVALID)) -    _dbus_assert_not_reached ("out of memory"); - -  _dbus_verbose ("Bytes after set_destination() and append_args()\n"); -  _dbus_verbose_bytes_of_string (&message->header, 0, -                                 _dbus_string_get_length (&message->header)); - -  if (!dbus_message_set_sender (message, "org.freedesktop.DBus")) -    _dbus_assert_not_reached ("out of memory"); - -  _dbus_verbose ("Bytes after set_sender()\n"); -  _dbus_verbose_bytes_of_string (&message->header, 0, -                                 _dbus_string_get_length (&message->header)); - -  /* When the bug happened the above set_destination() would -   * corrupt the signature -   */ -  if (!dbus_message_has_signature (message, "s")) -    { -      _dbus_warn ("Signature should be 's' but is '%s'\n", -                  dbus_message_get_signature (message)); -      _dbus_assert_not_reached ("signal has wrong signature"); -    } - -  /* have to set destination again to reproduce the bug */ -  if (!dbus_message_set_destination (message, ":1.0")) -    _dbus_assert_not_reached ("out of memory"); - -  _dbus_verbose ("Bytes after set_destination()\n"); -  _dbus_verbose_bytes_of_string (&message->header, 0, -                                 _dbus_string_get_length (&message->header)); - -  /* When the bug happened the above set_destination() would -   * corrupt the signature -   */ -  if (!dbus_message_has_signature (message, "s")) -    { -      _dbus_warn ("Signature should be 's' but is '%s'\n", -                  dbus_message_get_signature (message)); -      _dbus_assert_not_reached ("signal has wrong signature"); -    } - -  dbus_error_init (&error); -  if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, -                              &t, DBUS_TYPE_INVALID)) - -    { -      _dbus_warn ("Failed to get expected string arg for signal: %s\n", error.message); -      exit (1); -    } -  dbus_free (t); - -  dbus_message_unref (message); - -  /* Now load every message in test_data_dir if we have one */ -  if (test_data_dir == NULL) -    return TRUE; - -  return dbus_internal_do_not_use_foreach_message_file (test_data_dir, -                                                        (DBusForeachMessageFileFunc) -                                                        dbus_internal_do_not_use_try_message_file, -                                                        NULL); - -#endif /* Commented out most tests for now */ - -  return TRUE; -} -#endif /* DBUS_BUILD_TESTS */ +/* tests in dbus-message-util.c */ diff --git a/dbus/dbus-string-private.h b/dbus/dbus-string-private.h index a2fcd03b..a4b7e8c3 100644 --- a/dbus/dbus-string-private.h +++ b/dbus/dbus-string-private.h @@ -53,6 +53,62 @@ typedef struct    unsigned int   align_offset : 3; /**< str - align_offset is the actual malloc block */  } DBusRealString; + +/** + * @defgroup DBusStringInternals DBusString implementation details + * @ingroup  DBusInternals + * @brief DBusString implementation details + * + * The guts of DBusString. + * + * @{ + */ + +/** + * This is the maximum max length (and thus also the maximum length) + * of a DBusString + */ +#define _DBUS_STRING_MAX_MAX_LENGTH (_DBUS_INT_MAX - _DBUS_STRING_ALLOCATION_PADDING) + +/** + * Checks a bunch of assertions about a string object + * + * @param real the DBusRealString + */ +#define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length) + +/** + * Checks assertions about a string object that needs to be + * modifiable - may not be locked or const. Also declares + * the "real" variable pointing to DBusRealString.  + * @param str the string + */ +#define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ +  DBUS_GENERIC_STRING_PREAMBLE (real);                                          \ +  _dbus_assert (!(real)->constant);                                             \ +  _dbus_assert (!(real)->locked) + +/** + * Checks assertions about a string object that may be locked but + * can't be const. i.e. a string object that we can free.  Also + * declares the "real" variable pointing to DBusRealString. + * + * @param str the string + */ +#define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ +  DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \ +  _dbus_assert (!(real)->constant) + +/** + * Checks assertions about a string that may be const or locked.  Also + * declares the "real" variable pointing to DBusRealString. + * @param str the string. + */ +#define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \ +  DBUS_GENERIC_STRING_PREAMBLE (real) + +/** @} */ +  DBUS_END_DECLS  #endif /* DBUS_STRING_PRIVATE_H */ diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c new file mode 100644 index 00000000..1ff2ec67 --- /dev/null +++ b/dbus/dbus-string-util.c @@ -0,0 +1,727 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus + *  + * Copyright (C) 2002, 2003, 2004, 2005 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-internals.h" +#include "dbus-string.h" +#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 +#include "dbus-string-private.h" + +/** + * @addtogroup DBusString + * @{ + */ + +/** + * Copies the contents of a DBusString into a different + * buffer. The resulting buffer will be nul-terminated. + *  + * @param str a string + * @param buffer a C buffer to copy data to + * @param avail_len maximum length of C buffer + */ +void +_dbus_string_copy_to_buffer (const DBusString  *str, +			     char              *buffer, +			     int                avail_len) +{ +  int copy_len; +  DBUS_CONST_STRING_PREAMBLE (str); + +  _dbus_assert (avail_len >= 0); + +  copy_len = MIN (avail_len, real->len+1); +  memcpy (buffer, real->str, copy_len); +  if (avail_len > 0 && avail_len == copy_len) +    buffer[avail_len-1] = '\0'; +} + +/** + * Returns whether a string ends with the given suffix + * + * @todo memcmp might make this faster. + *  + * @param a the string + * @param c_str the C-style string + * @returns #TRUE if the string ends with the suffix + */ +dbus_bool_t +_dbus_string_ends_with_c_str (const DBusString *a, +                              const char       *c_str) +{ +  const unsigned char *ap; +  const unsigned char *bp; +  const unsigned char *a_end; +  unsigned long c_str_len; +  const DBusRealString *real_a = (const DBusRealString*) a; +  DBUS_GENERIC_STRING_PREAMBLE (real_a); +  _dbus_assert (c_str != NULL); +   +  c_str_len = strlen (c_str); +  if (((unsigned long)real_a->len) < c_str_len) +    return FALSE; +   +  ap = real_a->str + (real_a->len - c_str_len); +  bp = (const unsigned char*) c_str; +  a_end = real_a->str + real_a->len; +  while (ap != a_end) +    { +      if (*ap != *bp) +        return FALSE; +       +      ++ap; +      ++bp; +    } + +  _dbus_assert (*ap == '\0'); +  _dbus_assert (*bp == '\0'); +   +  return TRUE; +} + +/** + * Find the given byte scanning backward from the given start. + * Sets *found to -1 if the byte is not found. + * + * @param str the string + * @param start the place to start scanning (will not find the byte at this point) + * @param byte the byte to find + * @param found return location for where it was found + * @returns #TRUE if found + */ +dbus_bool_t +_dbus_string_find_byte_backward (const DBusString  *str, +                                 int                start, +                                 unsigned char      byte, +                                 int               *found) +{ +  int i; +  DBUS_CONST_STRING_PREAMBLE (str); +  _dbus_assert (start <= real->len); +  _dbus_assert (start >= 0); +  _dbus_assert (found != NULL); + +  i = start - 1; +  while (i >= 0) +    { +      if (real->str[i] == byte) +        break; +       +      --i; +    } + +  if (found) +    *found = i; + +  return i >= 0; +} + +/** + * Skips whitespace from start, storing the first non-whitespace in *end. + * (whitespace is space, tab, newline, CR). + * + * @param str the string + * @param start where to start + * @param end where to store the first non-whitespace byte index + */ +void +_dbus_string_skip_white (const DBusString *str, +                         int               start, +                         int              *end) +{ +  int i; +  DBUS_CONST_STRING_PREAMBLE (str); +  _dbus_assert (start <= real->len); +  _dbus_assert (start >= 0); +   +  i = start; +  while (i < real->len) +    { +      if (!(real->str[i] == ' ' || +            real->str[i] == '\n' || +            real->str[i] == '\r' || +            real->str[i] == '\t')) +        break; +       +      ++i; +    } + +  _dbus_assert (i == real->len || !(real->str[i] == ' ' || +                                    real->str[i] == '\t')); +   +  if (end) +    *end = i; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include <stdio.h> + +static void +test_max_len (DBusString *str, +              int         max_len) +{ +  if (max_len > 0) +    { +      if (!_dbus_string_set_length (str, max_len - 1)) +        _dbus_assert_not_reached ("setting len to one less than max should have worked"); +    } + +  if (!_dbus_string_set_length (str, max_len)) +    _dbus_assert_not_reached ("setting len to max len should have worked"); + +  if (_dbus_string_set_length (str, max_len + 1)) +    _dbus_assert_not_reached ("setting len to one more than max len should not have worked"); + +  if (!_dbus_string_set_length (str, 0)) +    _dbus_assert_not_reached ("setting len to zero should have worked"); +} + +static void +test_hex_roundtrip (const unsigned char *data, +                    int                  len) +{ +  DBusString orig; +  DBusString encoded; +  DBusString decoded; +  int end; + +  if (len < 0) +    len = strlen (data); +   +  if (!_dbus_string_init (&orig)) +    _dbus_assert_not_reached ("could not init string"); + +  if (!_dbus_string_init (&encoded)) +    _dbus_assert_not_reached ("could not init string"); +   +  if (!_dbus_string_init (&decoded)) +    _dbus_assert_not_reached ("could not init string"); + +  if (!_dbus_string_append_len (&orig, data, len)) +    _dbus_assert_not_reached ("couldn't append orig data"); + +  if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0)) +    _dbus_assert_not_reached ("could not encode"); + +  if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0)) +    _dbus_assert_not_reached ("could not decode"); +     +  _dbus_assert (_dbus_string_get_length (&encoded) == end); + +  if (!_dbus_string_equal (&orig, &decoded)) +    { +      const char *s; +       +      printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n", +              _dbus_string_get_length (&orig), +              _dbus_string_get_length (&encoded), +              _dbus_string_get_length (&decoded)); +      printf ("Original: %s\n", data); +      s = _dbus_string_get_const_data (&decoded); +      printf ("Decoded: %s\n", s); +      _dbus_assert_not_reached ("original string not the same as string decoded from hex"); +    } +   +  _dbus_string_free (&orig); +  _dbus_string_free (&encoded); +  _dbus_string_free (&decoded);   +} + +typedef void (* TestRoundtripFunc) (const unsigned char *data, +                                    int                  len); +static void +test_roundtrips (TestRoundtripFunc func) +{ +  (* func) ("Hello this is a string\n", -1); +  (* func) ("Hello this is a string\n1", -1); +  (* func) ("Hello this is a string\n12", -1); +  (* func) ("Hello this is a string\n123", -1); +  (* func) ("Hello this is a string\n1234", -1); +  (* func) ("Hello this is a string\n12345", -1); +  (* func) ("", 0); +  (* func) ("1", 1); +  (* func) ("12", 2); +  (* func) ("123", 3); +  (* func) ("1234", 4); +  (* func) ("12345", 5); +  (* func) ("", 1); +  (* func) ("1", 2); +  (* func) ("12", 3); +  (* func) ("123", 4); +  (* func) ("1234", 5); +  (* func) ("12345", 6); +  { +    unsigned char buf[512]; +    int i; +     +    i = 0; +    while (i < _DBUS_N_ELEMENTS (buf)) +      { +        buf[i] = i; +        ++i; +      } +    i = 0; +    while (i < _DBUS_N_ELEMENTS (buf)) +      { +        (* func) (buf, i); +        ++i; +      } +  } +} + +#ifdef DBUS_BUILD_TESTS +/* The max length thing is sort of a historical artifact + * from a feature that turned out to be dumb; perhaps + * we should purge it entirely. The problem with + * the feature is that it looks like memory allocation + * failure, but is not a transient or resolvable failure. + */ +static void +set_max_length (DBusString *str, +                int         max_length) +{ +  DBusRealString *real; +   +  real = (DBusRealString*) str; + +  real->max_length = max_length; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * @ingroup DBusStringInternals + * Unit test for DBusString. + * + * @todo Need to write tests for _dbus_string_copy() and + * _dbus_string_move() moving to/from each of start/middle/end of a + * string. Also need tests for _dbus_string_move_len () + *  + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_string_test (void) +{ +  DBusString str; +  DBusString other; +  int i, end; +  long v; +  double d; +  int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 }; +  char *s; +  dbus_unichar_t ch; +   +  i = 0; +  while (i < _DBUS_N_ELEMENTS (lens)) +    { +      if (!_dbus_string_init (&str)) +        _dbus_assert_not_reached ("failed to init string"); + +      set_max_length (&str, lens[i]); +       +      test_max_len (&str, lens[i]); +      _dbus_string_free (&str); + +      ++i; +    } + +  /* Test shortening and setting length */ +  i = 0; +  while (i < _DBUS_N_ELEMENTS (lens)) +    { +      int j; +       +      if (!_dbus_string_init (&str)) +        _dbus_assert_not_reached ("failed to init string"); + +      set_max_length (&str, lens[i]); +       +      if (!_dbus_string_set_length (&str, lens[i])) +        _dbus_assert_not_reached ("failed to set string length"); + +      j = lens[i]; +      while (j > 0) +        { +          _dbus_assert (_dbus_string_get_length (&str) == j); +          if (j > 0) +            { +              _dbus_string_shorten (&str, 1); +              _dbus_assert (_dbus_string_get_length (&str) == (j - 1)); +            } +          --j; +        } +       +      _dbus_string_free (&str); + +      ++i; +    } + +  /* Test appending data */ +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  i = 0; +  while (i < 10) +    { +      if (!_dbus_string_append (&str, "a")) +        _dbus_assert_not_reached ("failed to append string to string\n"); + +      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1); + +      if (!_dbus_string_append_byte (&str, 'b')) +        _dbus_assert_not_reached ("failed to append byte to string\n"); + +      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2); +                     +      ++i; +    } + +  _dbus_string_free (&str); + +  /* Check steal_data */ +   +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); + +  i = _dbus_string_get_length (&str); +   +  if (!_dbus_string_steal_data (&str, &s)) +    _dbus_assert_not_reached ("failed to steal data"); + +  _dbus_assert (_dbus_string_get_length (&str) == 0); +  _dbus_assert (((int)strlen (s)) == i); + +  dbus_free (s); + +  /* Check move */ +   +  if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); + +  i = _dbus_string_get_length (&str); + +  if (!_dbus_string_init (&other)) +    _dbus_assert_not_reached ("could not init string"); +   +  if (!_dbus_string_move (&str, 0, &other, 0)) +    _dbus_assert_not_reached ("could not move"); + +  _dbus_assert (_dbus_string_get_length (&str) == 0); +  _dbus_assert (_dbus_string_get_length (&other) == i); + +  if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); +   +  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other))) +    _dbus_assert_not_reached ("could not move"); + +  _dbus_assert (_dbus_string_get_length (&str) == 0); +  _dbus_assert (_dbus_string_get_length (&other) == i * 2); + +    if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); +   +  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2)) +    _dbus_assert_not_reached ("could not move"); + +  _dbus_assert (_dbus_string_get_length (&str) == 0); +  _dbus_assert (_dbus_string_get_length (&other) == i * 3); +   +  _dbus_string_free (&other); + +  /* Check copy */ +   +  if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); + +  i = _dbus_string_get_length (&str); +   +  if (!_dbus_string_init (&other)) +    _dbus_assert_not_reached ("could not init string"); +   +  if (!_dbus_string_copy (&str, 0, &other, 0)) +    _dbus_assert_not_reached ("could not copy"); + +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i); + +  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other))) +    _dbus_assert_not_reached ("could not copy"); + +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i * 2); +  _dbus_assert (_dbus_string_equal_c_str (&other, +                                          "Hello WorldHello World")); + +  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2)) +    _dbus_assert_not_reached ("could not copy"); + +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i * 3); +  _dbus_assert (_dbus_string_equal_c_str (&other, +                                          "Hello WorldHello WorldHello World")); +   +  _dbus_string_free (&str); +  _dbus_string_free (&other); + +  /* Check replace */ + +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); +   +  if (!_dbus_string_append (&str, "Hello World")) +    _dbus_assert_not_reached ("could not append to string"); + +  i = _dbus_string_get_length (&str); +   +  if (!_dbus_string_init (&other)) +    _dbus_assert_not_reached ("could not init string"); +   +  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), +                                 &other, 0, _dbus_string_get_length (&other))) +    _dbus_assert_not_reached ("could not replace"); + +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i); +  _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World")); +   +  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), +                                 &other, 5, 1)) +    _dbus_assert_not_reached ("could not replace center space"); + +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); +  _dbus_assert (_dbus_string_equal_c_str (&other, +                                          "HelloHello WorldWorld")); + +   +  if (!_dbus_string_replace_len (&str, 1, 1, +                                 &other, +                                 _dbus_string_get_length (&other) - 1, +                                 1)) +    _dbus_assert_not_reached ("could not replace end character"); +   +  _dbus_assert (_dbus_string_get_length (&str) == i); +  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); +  _dbus_assert (_dbus_string_equal_c_str (&other, +                                          "HelloHello WorldWorle")); +   +  _dbus_string_free (&str); +  _dbus_string_free (&other); +   +  /* Check append/get unichar */ +   +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  ch = 0; +  if (!_dbus_string_append_unichar (&str, 0xfffc)) +    _dbus_assert_not_reached ("failed to append unichar"); + +  _dbus_string_get_unichar (&str, 0, &ch, &i); + +  _dbus_assert (ch == 0xfffc); +  _dbus_assert (i == _dbus_string_get_length (&str)); + +  _dbus_string_free (&str); + +  /* Check insert/set/get byte */ +   +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  if (!_dbus_string_append (&str, "Hello")) +    _dbus_assert_not_reached ("failed to append Hello"); + +  _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H'); +  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e'); +  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l'); +  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l'); +  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o'); + +  _dbus_string_set_byte (&str, 1, 'q'); +  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q'); + +  if (!_dbus_string_insert_bytes (&str, 0, 1, 255)) +    _dbus_assert_not_reached ("can't insert byte"); + +  if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z')) +    _dbus_assert_not_reached ("can't insert byte"); + +  if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W')) +    _dbus_assert_not_reached ("can't insert byte"); +   +  _dbus_assert (_dbus_string_get_byte (&str, 0) == 255); +  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H'); +  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z'); +  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z'); +  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z'); +  _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z'); +  _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q'); +  _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l'); +  _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l'); +  _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o'); +  _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W'); + +  _dbus_string_free (&str); +   +  /* Check append/parse int/double */ +   +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  if (!_dbus_string_append_int (&str, 27)) +    _dbus_assert_not_reached ("failed to append int"); + +  i = _dbus_string_get_length (&str); + +  if (!_dbus_string_parse_int (&str, 0, &v, &end)) +    _dbus_assert_not_reached ("failed to parse int"); + +  _dbus_assert (v == 27); +  _dbus_assert (end == i); + +  _dbus_string_free (&str); +   +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); +   +  if (!_dbus_string_append_double (&str, 50.3)) +    _dbus_assert_not_reached ("failed to append float"); + +  i = _dbus_string_get_length (&str); + +  if (!_dbus_string_parse_double (&str, 0, &d, &end)) +    _dbus_assert_not_reached ("failed to parse float"); + +  _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6)); +  _dbus_assert (end == i); + +  _dbus_string_free (&str); + +  /* Test find */ +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("failed to init string"); + +  if (!_dbus_string_append (&str, "Hello")) +    _dbus_assert_not_reached ("couldn't append to string"); +   +  if (!_dbus_string_find (&str, 0, "He", &i)) +    _dbus_assert_not_reached ("didn't find 'He'"); +  _dbus_assert (i == 0); + +  if (!_dbus_string_find (&str, 0, "Hello", &i)) +    _dbus_assert_not_reached ("didn't find 'Hello'"); +  _dbus_assert (i == 0); +   +  if (!_dbus_string_find (&str, 0, "ello", &i)) +    _dbus_assert_not_reached ("didn't find 'ello'"); +  _dbus_assert (i == 1); + +  if (!_dbus_string_find (&str, 0, "lo", &i)) +    _dbus_assert_not_reached ("didn't find 'lo'"); +  _dbus_assert (i == 3); + +  if (!_dbus_string_find (&str, 2, "lo", &i)) +    _dbus_assert_not_reached ("didn't find 'lo'"); +  _dbus_assert (i == 3); + +  if (_dbus_string_find (&str, 4, "lo", &i)) +    _dbus_assert_not_reached ("did find 'lo'"); +   +  if (!_dbus_string_find (&str, 0, "l", &i)) +    _dbus_assert_not_reached ("didn't find 'l'"); +  _dbus_assert (i == 2); + +  if (!_dbus_string_find (&str, 0, "H", &i)) +    _dbus_assert_not_reached ("didn't find 'H'"); +  _dbus_assert (i == 0); + +  if (!_dbus_string_find (&str, 0, "", &i)) +    _dbus_assert_not_reached ("didn't find ''"); +  _dbus_assert (i == 0); +   +  if (_dbus_string_find (&str, 0, "Hello!", NULL)) +    _dbus_assert_not_reached ("Did find 'Hello!'"); + +  if (_dbus_string_find (&str, 0, "Oh, Hello", NULL)) +    _dbus_assert_not_reached ("Did find 'Oh, Hello'"); +   +  if (_dbus_string_find (&str, 0, "ill", NULL)) +    _dbus_assert_not_reached ("Did find 'ill'"); + +  if (_dbus_string_find (&str, 0, "q", NULL)) +    _dbus_assert_not_reached ("Did find 'q'"); + +  if (!_dbus_string_find_to (&str, 0, 2, "He", NULL)) +    _dbus_assert_not_reached ("Didn't find 'He'"); + +  if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL)) +    _dbus_assert_not_reached ("Did find 'Hello'"); + +  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i)) +    _dbus_assert_not_reached ("Did not find 'H'"); +  _dbus_assert (i == 0); + +  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i)) +    _dbus_assert_not_reached ("Did not find 'o'"); +  _dbus_assert (i == _dbus_string_get_length (&str) - 1); + +  if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i)) +    _dbus_assert_not_reached ("Did find 'o'"); +  _dbus_assert (i == -1); + +  if (_dbus_string_find_byte_backward (&str, 1, 'e', &i)) +    _dbus_assert_not_reached ("Did find 'e'"); +  _dbus_assert (i == -1); + +  if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i)) +    _dbus_assert_not_reached ("Didn't find 'e'"); +  _dbus_assert (i == 1); +   +  _dbus_string_free (&str); + +  /* Hex encoding */ +  _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string"); +  if (!_dbus_string_init (&other)) +    _dbus_assert_not_reached ("could not init string"); + +  if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0)) +    _dbus_assert_not_reached ("deccoded bogus hex string with no error"); + +  _dbus_assert (end == 8); + +  _dbus_string_free (&other); + +  test_roundtrips (test_hex_roundtrip); +   +  _dbus_string_free (&str); +   +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 52099d65..154193ce 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -69,61 +69,6 @@   */  /** - * @defgroup DBusStringInternals DBusString implementation details - * @ingroup  DBusInternals - * @brief DBusString implementation details - * - * The guts of DBusString. - * - * @{ - */ - -/** - * This is the maximum max length (and thus also the maximum length) - * of a DBusString - */ -#define MAX_MAX_LENGTH (_DBUS_INT_MAX - _DBUS_STRING_ALLOCATION_PADDING) - -/** - * Checks a bunch of assertions about a string object - * - * @param real the DBusRealString - */ -#define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length) - -/** - * Checks assertions about a string object that needs to be - * modifiable - may not be locked or const. Also declares - * the "real" variable pointing to DBusRealString.  - * @param str the string - */ -#define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ -  DBUS_GENERIC_STRING_PREAMBLE (real);                                          \ -  _dbus_assert (!(real)->constant);                                             \ -  _dbus_assert (!(real)->locked) - -/** - * Checks assertions about a string object that may be locked but - * can't be const. i.e. a string object that we can free.  Also - * declares the "real" variable pointing to DBusRealString. - * - * @param str the string - */ -#define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ -  DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \ -  _dbus_assert (!(real)->constant) - -/** - * Checks assertions about a string that may be const or locked.  Also - * declares the "real" variable pointing to DBusRealString. - * @param str the string. - */ -#define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \ -  DBUS_GENERIC_STRING_PREAMBLE (real) - -/** @} */ - -/**   * @addtogroup DBusString   * @{   */ @@ -207,7 +152,7 @@ _dbus_string_init_preallocated (DBusString *str,    real->len = 0;    real->str[real->len] = '\0'; -  real->max_length = MAX_MAX_LENGTH; +  real->max_length = _DBUS_STRING_MAX_MAX_LENGTH;    real->constant = FALSE;    real->locked = FALSE;    real->invalid = FALSE; @@ -231,6 +176,7 @@ _dbus_string_init (DBusString *str)    return _dbus_string_init_preallocated (str, 0);  } +#ifdef DBUS_BUILD_TESTS  /* The max length thing is sort of a historical artifact   * from a feature that turned out to be dumb; perhaps   * we should purge it entirely. The problem with @@ -247,6 +193,7 @@ set_max_length (DBusString *str,    real->max_length = max_length;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Initializes a constant string. The value parameter is not copied @@ -286,7 +233,7 @@ _dbus_string_init_const_len (DBusString *str,    _dbus_assert (str != NULL);    _dbus_assert (value != NULL); -  _dbus_assert (len <= MAX_MAX_LENGTH); +  _dbus_assert (len <= _DBUS_STRING_MAX_MAX_LENGTH);    _dbus_assert (len >= 0);    real = (DBusRealString*) str; @@ -376,8 +323,8 @@ reallocate_for_length (DBusRealString *real,    /* at least double our old allocation to avoid O(n), avoiding     * overflow     */ -  if (real->allocated > (MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2) -    new_allocated = MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING; +  if (real->allocated > (_DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2) +    new_allocated = _DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING;    else      new_allocated = real->allocated * 2; @@ -454,6 +401,7 @@ open_gap (int             len,    return TRUE;  } +#ifndef _dbus_string_get_data  /**   * Gets the raw character buffer from the string.  The returned buffer   * will be nul-terminated, but note that strings may contain binary @@ -472,6 +420,7 @@ _dbus_string_get_data (DBusString *str)    return real->str;  } +#endif /* _dbus_string_get_data */  /* only do the function if we don't have the macro */  #ifndef _dbus_string_get_const_data @@ -683,6 +632,7 @@ _dbus_string_steal_data (DBusString        *str,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Like _dbus_string_get_data_len(), but removes the gotten data from   * the original string. The caller must free the data returned. This @@ -733,7 +683,7 @@ _dbus_string_steal_data_len (DBusString        *str,    _dbus_string_free (&dest);    return TRUE;  } - +#endif /* DBUS_BUILD_TESTS */  /**   * Copies the data from the string into a char* @@ -758,6 +708,7 @@ _dbus_string_copy_data (const DBusString  *str,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Copies a segment of the string into a char*   * @@ -802,30 +753,7 @@ _dbus_string_copy_data_len (const DBusString  *str,    _dbus_string_free (&dest);    return TRUE;  } - -/** - * Copies the contents of a DBusString into a different - * buffer. The resulting buffer will be nul-terminated. - *  - * @param str a string - * @param buffer a C buffer to copy data to - * @param avail_len maximum length of C buffer - */ -void -_dbus_string_copy_to_buffer (const DBusString  *str, -			     char              *buffer, -			     int                avail_len) -{ -  int copy_len; -  DBUS_CONST_STRING_PREAMBLE (str); - -  _dbus_assert (avail_len >= 0); - -  copy_len = MIN (avail_len, real->len+1); -  memcpy (buffer, real->str, copy_len); -  if (avail_len > 0 && avail_len == copy_len) -    buffer[avail_len-1] = '\0'; -} +#endif /* DBUS_BUILD_TESTS */  /* Only have the function if we don't have the macro */  #ifndef _dbus_string_get_length @@ -1046,6 +974,7 @@ _dbus_string_append (DBusString *str,    return append (real, buffer, buffer_len);  } +  /** assign 4 bytes from one string to another */  #define ASSIGN_4_OCTETS(p, octets) \    *((dbus_uint32_t*)(p)) = *((dbus_uint32_t*)(octets)); @@ -1074,6 +1003,7 @@ do {                                            \  } while (0)  #endif /* DBUS_HAVE_INT64 */ +#ifdef DBUS_BUILD_TESTS  /**   * Appends 4 bytes aligned on a 4 byte boundary   * with any alignment padding initialized to 0. @@ -1095,7 +1025,9 @@ _dbus_string_append_4_aligned (DBusString         *str,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */ +#ifdef DBUS_BUILD_TESTS  /**   * Appends 8 bytes aligned on an 8 byte boundary   * with any alignment padding initialized to 0. @@ -1117,6 +1049,7 @@ _dbus_string_append_8_aligned (DBusString         *str,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Inserts 4 bytes aligned on a 4 byte boundary @@ -1299,6 +1232,7 @@ _dbus_string_append_byte (DBusString    *str,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Appends a single Unicode character, encoding the character   * in UTF-8 format. @@ -1369,6 +1303,7 @@ _dbus_string_append_unichar (DBusString    *str,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */  static void  delete (DBusRealString *real, @@ -1730,6 +1665,7 @@ _dbus_string_replace_len (const DBusString *source,       ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \       ((Char) & 0xFFFF) != 0xFFFF) +#ifdef DBUS_BUILD_TESTS  /**   * Gets a unicode character from a UTF-8 string. Does no validation;   * you must verify that the string is valid UTF-8 in advance and must @@ -1776,6 +1712,7 @@ _dbus_string_get_unichar (const DBusString *str,    if (end_return)      *end_return = start + len;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Finds the given substring in the string, @@ -1877,43 +1814,6 @@ _dbus_string_find_to (const DBusString *str,  }  /** - * Find the given byte scanning backward from the given start. - * Sets *found to -1 if the byte is not found. - * - * @param str the string - * @param start the place to start scanning (will not find the byte at this point) - * @param byte the byte to find - * @param found return location for where it was found - * @returns #TRUE if found - */ -dbus_bool_t -_dbus_string_find_byte_backward (const DBusString  *str, -                                 int                start, -                                 unsigned char      byte, -                                 int               *found) -{ -  int i; -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start <= real->len); -  _dbus_assert (start >= 0); -  _dbus_assert (found != NULL); - -  i = start - 1; -  while (i >= 0) -    { -      if (real->str[i] == byte) -        break; -       -      --i; -    } - -  if (found) -    *found = i; - -  return i >= 0; -} - -/**   * Finds a blank (space or tab) in the string. Returns #TRUE   * if found, #FALSE otherwise. If a blank is not found sets   * *found to the length of the string. @@ -1989,43 +1889,6 @@ _dbus_string_skip_blank (const DBusString *str,  }  /** - * Skips whitespace from start, storing the first non-whitespace in *end. - * (whitespace is space, tab, newline, CR). - * - * @param str the string - * @param start where to start - * @param end where to store the first non-whitespace byte index - */ -void -_dbus_string_skip_white (const DBusString *str, -                         int               start, -                         int              *end) -{ -  int i; -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start <= real->len); -  _dbus_assert (start >= 0); -   -  i = start; -  while (i < real->len) -    { -      if (!(real->str[i] == ' ' || -            real->str[i] == '\n' || -            real->str[i] == '\r' || -            real->str[i] == '\t')) -        break; -       -      ++i; -    } - -  _dbus_assert (i == real->len || !(real->str[i] == ' ' || -                                    real->str[i] == '\t')); -   -  if (end) -    *end = i; -} - -/**   * Assigns a newline-terminated or \\r\\n-terminated line from the front   * of the string to the given dest string. The dest string's previous   * contents are deleted. If the source string contains no newline, @@ -2092,6 +1955,7 @@ _dbus_string_pop_line (DBusString *source,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Deletes up to and including the first blank space   * in the string. @@ -2108,7 +1972,9 @@ _dbus_string_delete_first_word (DBusString *str)    _dbus_string_delete (str, 0, i);  } +#endif +#ifdef DBUS_BUILD_TESTS  /**   * Deletes any leading blanks in the string   * @@ -2124,6 +1990,7 @@ _dbus_string_delete_leading_blanks (DBusString *str)    if (i > 0)      _dbus_string_delete (str, 0, i);  } +#endif  /**   * Tests two DBusString for equality. @@ -2164,6 +2031,7 @@ _dbus_string_equal (const DBusString *a,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Tests two DBusString for equality up to the given length.   * The strings may be shorter than the given length. @@ -2208,6 +2076,7 @@ _dbus_string_equal_len (const DBusString *a,    return TRUE;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Tests two sub-parts of two DBusString for equality.  The specified @@ -2302,6 +2171,7 @@ _dbus_string_equal_c_str (const DBusString *a,    return TRUE;  } +#ifdef DBUS_BUILD_TESTS  /**   * Checks whether a string starts with the given C string.   * @@ -2337,49 +2207,7 @@ _dbus_string_starts_with_c_str (const DBusString *a,    else      return FALSE;  } - -/** - * Returns whether a string ends with the given suffix - * - * @todo memcmp might make this faster. - *  - * @param a the string - * @param c_str the C-style string - * @returns #TRUE if the string ends with the suffix - */ -dbus_bool_t -_dbus_string_ends_with_c_str (const DBusString *a, -                              const char       *c_str) -{ -  const unsigned char *ap; -  const unsigned char *bp; -  const unsigned char *a_end; -  unsigned long c_str_len; -  const DBusRealString *real_a = (const DBusRealString*) a; -  DBUS_GENERIC_STRING_PREAMBLE (real_a); -  _dbus_assert (c_str != NULL); -   -  c_str_len = strlen (c_str); -  if (((unsigned long)real_a->len) < c_str_len) -    return FALSE; -   -  ap = real_a->str + (real_a->len - c_str_len); -  bp = (const unsigned char*) c_str; -  a_end = real_a->str + real_a->len; -  while (ap != a_end) -    { -      if (*ap != *bp) -        return FALSE; -       -      ++ap; -      ++bp; -    } - -  _dbus_assert (*ap == '\0'); -  _dbus_assert (*bp == '\0'); -   -  return TRUE; -} +#endif /* DBUS_BUILD_TESTS */  /**   * Encodes a string in hex, the way MD5 and SHA-1 are usually @@ -2773,643 +2601,4 @@ _dbus_string_zero (DBusString *str)  }  /** @} */ -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include <stdio.h> - -/** - * Parses a basic type defined by type contained in a DBusString. The - * end_return parameter may be #NULL if you aren't interested in it. The - * type is parsed and stored in value_return. Return parameters are not - * initialized if the function returns #FALSE. - * - * @param str the string - * @param type the type of the basic type - * @param start the byte index of the start of the type - * @param value_return return location of the value or #NULL - * @param end_return return location of the end of the type, or #NULL - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_string_parse_basic_type (const DBusString  *str, -			       char               type, -			       int                start, -			       void              *value, -			       int               *end_return) -{ -  int end = start; - -  switch (type) -    { -    case DBUS_TYPE_BOOLEAN: -      { -	int len = _dbus_string_get_length (str) - start; -	if (len >= 5 && _dbus_string_find_to (str, start, start + 5, "false", NULL)) -	  { -	    end += 5; -	    *(unsigned char *) value = TRUE; -	  } -	else if (len >= 4 && _dbus_string_find_to (str, start, start + 4, "true", NULL)) -	  { -	    end += 4; -	    *(unsigned char *) value = FALSE; -	  } -	else -	  _dbus_warn ("could not parse BOOLEAN\n"); -	break; -      } -    case DBUS_TYPE_BYTE: -      { -	long val = 0; - -	if (_dbus_string_get_byte (str, start) == '\'' && -	    _dbus_string_get_length (str) >= start + 4 && -	    _dbus_string_get_byte (str, start + 1) == '\\' && -	    _dbus_string_get_byte (str, start + 2) == '\'' && -	    _dbus_string_get_byte (str, start + 3) == '\'') -	  { -	    val = '\''; -	    end += 4; -	  } -	else if (_dbus_string_get_byte (str, start) == '\'' && -		 _dbus_string_get_length (str) >= start + 3 && -		 _dbus_string_get_byte (str, start + 2) == '\'') -	  { -	    val = _dbus_string_get_byte (str, start + 1); -	    end += 3; -	  } -	else -	  { -	    if (!_dbus_string_parse_int (str, start, &val, &end))  -	      _dbus_warn ("Failed to parse integer for BYTE\n"); -	  } - -	if (val > 255) -	  _dbus_warn ("A byte must be in range 0-255 not %ld\n", val); - -	*(unsigned char *) value = val; -	break; -      } -    case DBUS_TYPE_INT32: -      { -	long val; -	if (_dbus_string_parse_int (str, start, &val, &end)) -	  *(dbus_int32_t *)value = val; -	break; -      } -    case DBUS_TYPE_UINT32: -      { -	unsigned long val; -	if (_dbus_string_parse_uint (str, start, &val, &end)) -	  *(dbus_uint32_t *)value = val; -	break; -      } -#ifdef DBUS_HAVE_INT64 -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:  -      /* use stroll oull */ -      _dbus_assert_not_reached ("string -> [u]int64 not supported yet"); -      break; -#endif /* DBUS_HAVE_INT64 */ -    case DBUS_TYPE_DOUBLE: -      _dbus_string_parse_double (str, start, value, &end); -      break; -    default: -      _dbus_assert_not_reached ("not a basic type"); -      break; -    } -  if (end_return) -    *end_return = end; - -  return end != start; -} - -static void -test_max_len (DBusString *str, -              int         max_len) -{ -  if (max_len > 0) -    { -      if (!_dbus_string_set_length (str, max_len - 1)) -        _dbus_assert_not_reached ("setting len to one less than max should have worked"); -    } - -  if (!_dbus_string_set_length (str, max_len)) -    _dbus_assert_not_reached ("setting len to max len should have worked"); - -  if (_dbus_string_set_length (str, max_len + 1)) -    _dbus_assert_not_reached ("setting len to one more than max len should not have worked"); - -  if (!_dbus_string_set_length (str, 0)) -    _dbus_assert_not_reached ("setting len to zero should have worked"); -} - -static void -test_hex_roundtrip (const unsigned char *data, -                    int                  len) -{ -  DBusString orig; -  DBusString encoded; -  DBusString decoded; -  int end; - -  if (len < 0) -    len = strlen (data); -   -  if (!_dbus_string_init (&orig)) -    _dbus_assert_not_reached ("could not init string"); - -  if (!_dbus_string_init (&encoded)) -    _dbus_assert_not_reached ("could not init string"); -   -  if (!_dbus_string_init (&decoded)) -    _dbus_assert_not_reached ("could not init string"); - -  if (!_dbus_string_append_len (&orig, data, len)) -    _dbus_assert_not_reached ("couldn't append orig data"); - -  if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0)) -    _dbus_assert_not_reached ("could not encode"); - -  if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0)) -    _dbus_assert_not_reached ("could not decode"); -     -  _dbus_assert (_dbus_string_get_length (&encoded) == end); - -  if (!_dbus_string_equal (&orig, &decoded)) -    { -      const char *s; -       -      printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n", -              _dbus_string_get_length (&orig), -              _dbus_string_get_length (&encoded), -              _dbus_string_get_length (&decoded)); -      printf ("Original: %s\n", data); -      s = _dbus_string_get_const_data (&decoded); -      printf ("Decoded: %s\n", s); -      _dbus_assert_not_reached ("original string not the same as string decoded from hex"); -    } -   -  _dbus_string_free (&orig); -  _dbus_string_free (&encoded); -  _dbus_string_free (&decoded);   -} - -typedef void (* TestRoundtripFunc) (const unsigned char *data, -                                    int                  len); -static void -test_roundtrips (TestRoundtripFunc func) -{ -  (* func) ("Hello this is a string\n", -1); -  (* func) ("Hello this is a string\n1", -1); -  (* func) ("Hello this is a string\n12", -1); -  (* func) ("Hello this is a string\n123", -1); -  (* func) ("Hello this is a string\n1234", -1); -  (* func) ("Hello this is a string\n12345", -1); -  (* func) ("", 0); -  (* func) ("1", 1); -  (* func) ("12", 2); -  (* func) ("123", 3); -  (* func) ("1234", 4); -  (* func) ("12345", 5); -  (* func) ("", 1); -  (* func) ("1", 2); -  (* func) ("12", 3); -  (* func) ("123", 4); -  (* func) ("1234", 5); -  (* func) ("12345", 6); -  { -    unsigned char buf[512]; -    int i; -     -    i = 0; -    while (i < _DBUS_N_ELEMENTS (buf)) -      { -        buf[i] = i; -        ++i; -      } -    i = 0; -    while (i < _DBUS_N_ELEMENTS (buf)) -      { -        (* func) (buf, i); -        ++i; -      } -  } -} - - -/** - * @ingroup DBusStringInternals - * Unit test for DBusString. - * - * @todo Need to write tests for _dbus_string_copy() and - * _dbus_string_move() moving to/from each of start/middle/end of a - * string. Also need tests for _dbus_string_move_len () - *  - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_string_test (void) -{ -  DBusString str; -  DBusString other; -  int i, end; -  long v; -  double d; -  int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 }; -  char *s; -  dbus_unichar_t ch; -   -  i = 0; -  while (i < _DBUS_N_ELEMENTS (lens)) -    { -      if (!_dbus_string_init (&str)) -        _dbus_assert_not_reached ("failed to init string"); - -      set_max_length (&str, lens[i]); -       -      test_max_len (&str, lens[i]); -      _dbus_string_free (&str); - -      ++i; -    } - -  /* Test shortening and setting length */ -  i = 0; -  while (i < _DBUS_N_ELEMENTS (lens)) -    { -      int j; -       -      if (!_dbus_string_init (&str)) -        _dbus_assert_not_reached ("failed to init string"); - -      set_max_length (&str, lens[i]); -       -      if (!_dbus_string_set_length (&str, lens[i])) -        _dbus_assert_not_reached ("failed to set string length"); - -      j = lens[i]; -      while (j > 0) -        { -          _dbus_assert (_dbus_string_get_length (&str) == j); -          if (j > 0) -            { -              _dbus_string_shorten (&str, 1); -              _dbus_assert (_dbus_string_get_length (&str) == (j - 1)); -            } -          --j; -        } -       -      _dbus_string_free (&str); - -      ++i; -    } - -  /* Test appending data */ -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  i = 0; -  while (i < 10) -    { -      if (!_dbus_string_append (&str, "a")) -        _dbus_assert_not_reached ("failed to append string to string\n"); - -      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1); - -      if (!_dbus_string_append_byte (&str, 'b')) -        _dbus_assert_not_reached ("failed to append byte to string\n"); - -      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2); -                     -      ++i; -    } - -  _dbus_string_free (&str); - -  /* Check steal_data */ -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); - -  i = _dbus_string_get_length (&str); -   -  if (!_dbus_string_steal_data (&str, &s)) -    _dbus_assert_not_reached ("failed to steal data"); - -  _dbus_assert (_dbus_string_get_length (&str) == 0); -  _dbus_assert (((int)strlen (s)) == i); - -  dbus_free (s); - -  /* Check move */ -   -  if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); - -  i = _dbus_string_get_length (&str); - -  if (!_dbus_string_init (&other)) -    _dbus_assert_not_reached ("could not init string"); -   -  if (!_dbus_string_move (&str, 0, &other, 0)) -    _dbus_assert_not_reached ("could not move"); - -  _dbus_assert (_dbus_string_get_length (&str) == 0); -  _dbus_assert (_dbus_string_get_length (&other) == i); - -  if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); -   -  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other))) -    _dbus_assert_not_reached ("could not move"); - -  _dbus_assert (_dbus_string_get_length (&str) == 0); -  _dbus_assert (_dbus_string_get_length (&other) == i * 2); - -    if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); -   -  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2)) -    _dbus_assert_not_reached ("could not move"); - -  _dbus_assert (_dbus_string_get_length (&str) == 0); -  _dbus_assert (_dbus_string_get_length (&other) == i * 3); -   -  _dbus_string_free (&other); - -  /* Check copy */ -   -  if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); - -  i = _dbus_string_get_length (&str); -   -  if (!_dbus_string_init (&other)) -    _dbus_assert_not_reached ("could not init string"); -   -  if (!_dbus_string_copy (&str, 0, &other, 0)) -    _dbus_assert_not_reached ("could not copy"); - -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i); - -  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other))) -    _dbus_assert_not_reached ("could not copy"); - -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i * 2); -  _dbus_assert (_dbus_string_equal_c_str (&other, -                                          "Hello WorldHello World")); - -  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2)) -    _dbus_assert_not_reached ("could not copy"); - -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i * 3); -  _dbus_assert (_dbus_string_equal_c_str (&other, -                                          "Hello WorldHello WorldHello World")); -   -  _dbus_string_free (&str); -  _dbus_string_free (&other); - -  /* Check replace */ - -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); -   -  if (!_dbus_string_append (&str, "Hello World")) -    _dbus_assert_not_reached ("could not append to string"); - -  i = _dbus_string_get_length (&str); -   -  if (!_dbus_string_init (&other)) -    _dbus_assert_not_reached ("could not init string"); -   -  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), -                                 &other, 0, _dbus_string_get_length (&other))) -    _dbus_assert_not_reached ("could not replace"); - -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i); -  _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World")); -   -  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), -                                 &other, 5, 1)) -    _dbus_assert_not_reached ("could not replace center space"); - -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); -  _dbus_assert (_dbus_string_equal_c_str (&other, -                                          "HelloHello WorldWorld")); - -   -  if (!_dbus_string_replace_len (&str, 1, 1, -                                 &other, -                                 _dbus_string_get_length (&other) - 1, -                                 1)) -    _dbus_assert_not_reached ("could not replace end character"); -   -  _dbus_assert (_dbus_string_get_length (&str) == i); -  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); -  _dbus_assert (_dbus_string_equal_c_str (&other, -                                          "HelloHello WorldWorle")); -   -  _dbus_string_free (&str); -  _dbus_string_free (&other); -   -  /* Check append/get unichar */ -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  ch = 0; -  if (!_dbus_string_append_unichar (&str, 0xfffc)) -    _dbus_assert_not_reached ("failed to append unichar"); - -  _dbus_string_get_unichar (&str, 0, &ch, &i); - -  _dbus_assert (ch == 0xfffc); -  _dbus_assert (i == _dbus_string_get_length (&str)); - -  _dbus_string_free (&str); - -  /* Check insert/set/get byte */ -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  if (!_dbus_string_append (&str, "Hello")) -    _dbus_assert_not_reached ("failed to append Hello"); - -  _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H'); -  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e'); -  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l'); -  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l'); -  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o'); - -  _dbus_string_set_byte (&str, 1, 'q'); -  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q'); - -  if (!_dbus_string_insert_bytes (&str, 0, 1, 255)) -    _dbus_assert_not_reached ("can't insert byte"); - -  if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z')) -    _dbus_assert_not_reached ("can't insert byte"); - -  if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W')) -    _dbus_assert_not_reached ("can't insert byte"); -   -  _dbus_assert (_dbus_string_get_byte (&str, 0) == 255); -  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H'); -  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z'); -  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z'); -  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z'); -  _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z'); -  _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q'); -  _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l'); -  _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l'); -  _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o'); -  _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W'); - -  _dbus_string_free (&str); -   -  /* Check append/parse int/double */ -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  if (!_dbus_string_append_int (&str, 27)) -    _dbus_assert_not_reached ("failed to append int"); - -  i = _dbus_string_get_length (&str); - -  if (!_dbus_string_parse_int (&str, 0, &v, &end)) -    _dbus_assert_not_reached ("failed to parse int"); - -  _dbus_assert (v == 27); -  _dbus_assert (end == i); - -  _dbus_string_free (&str); -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); -   -  if (!_dbus_string_append_double (&str, 50.3)) -    _dbus_assert_not_reached ("failed to append float"); - -  i = _dbus_string_get_length (&str); - -  if (!_dbus_string_parse_double (&str, 0, &d, &end)) -    _dbus_assert_not_reached ("failed to parse float"); - -  _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6)); -  _dbus_assert (end == i); - -  _dbus_string_free (&str); - -  /* Test find */ -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  if (!_dbus_string_append (&str, "Hello")) -    _dbus_assert_not_reached ("couldn't append to string"); -   -  if (!_dbus_string_find (&str, 0, "He", &i)) -    _dbus_assert_not_reached ("didn't find 'He'"); -  _dbus_assert (i == 0); - -  if (!_dbus_string_find (&str, 0, "Hello", &i)) -    _dbus_assert_not_reached ("didn't find 'Hello'"); -  _dbus_assert (i == 0); -   -  if (!_dbus_string_find (&str, 0, "ello", &i)) -    _dbus_assert_not_reached ("didn't find 'ello'"); -  _dbus_assert (i == 1); - -  if (!_dbus_string_find (&str, 0, "lo", &i)) -    _dbus_assert_not_reached ("didn't find 'lo'"); -  _dbus_assert (i == 3); - -  if (!_dbus_string_find (&str, 2, "lo", &i)) -    _dbus_assert_not_reached ("didn't find 'lo'"); -  _dbus_assert (i == 3); - -  if (_dbus_string_find (&str, 4, "lo", &i)) -    _dbus_assert_not_reached ("did find 'lo'"); -   -  if (!_dbus_string_find (&str, 0, "l", &i)) -    _dbus_assert_not_reached ("didn't find 'l'"); -  _dbus_assert (i == 2); - -  if (!_dbus_string_find (&str, 0, "H", &i)) -    _dbus_assert_not_reached ("didn't find 'H'"); -  _dbus_assert (i == 0); - -  if (!_dbus_string_find (&str, 0, "", &i)) -    _dbus_assert_not_reached ("didn't find ''"); -  _dbus_assert (i == 0); -   -  if (_dbus_string_find (&str, 0, "Hello!", NULL)) -    _dbus_assert_not_reached ("Did find 'Hello!'"); - -  if (_dbus_string_find (&str, 0, "Oh, Hello", NULL)) -    _dbus_assert_not_reached ("Did find 'Oh, Hello'"); -   -  if (_dbus_string_find (&str, 0, "ill", NULL)) -    _dbus_assert_not_reached ("Did find 'ill'"); - -  if (_dbus_string_find (&str, 0, "q", NULL)) -    _dbus_assert_not_reached ("Did find 'q'"); - -  if (!_dbus_string_find_to (&str, 0, 2, "He", NULL)) -    _dbus_assert_not_reached ("Didn't find 'He'"); - -  if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL)) -    _dbus_assert_not_reached ("Did find 'Hello'"); - -  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i)) -    _dbus_assert_not_reached ("Did not find 'H'"); -  _dbus_assert (i == 0); - -  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i)) -    _dbus_assert_not_reached ("Did not find 'o'"); -  _dbus_assert (i == _dbus_string_get_length (&str) - 1); - -  if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i)) -    _dbus_assert_not_reached ("Did find 'o'"); -  _dbus_assert (i == -1); - -  if (_dbus_string_find_byte_backward (&str, 1, 'e', &i)) -    _dbus_assert_not_reached ("Did find 'e'"); -  _dbus_assert (i == -1); - -  if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i)) -    _dbus_assert_not_reached ("Didn't find 'e'"); -  _dbus_assert (i == 1); -   -  _dbus_string_free (&str); - -  /* Hex encoding */ -  _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string"); -  if (!_dbus_string_init (&other)) -    _dbus_assert_not_reached ("could not init string"); - -  if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0)) -    _dbus_assert_not_reached ("deccoded bogus hex string with no error"); - -  _dbus_assert (end == 8); - -  _dbus_string_free (&other); - -  test_roundtrips (test_hex_roundtrip); -   -  _dbus_string_free (&str); -   -  return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ +/* tests are in dbus-string-util.c */ diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index df5f4232..52281210 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -54,6 +54,7 @@ struct DBusString   * to inline non-exported symbols across files in the library.   * Note that these break type safety (due to the casts)   */ +#define _dbus_string_get_data(s) ((char*)(((DBusString*)(s))->dummy1))  #define _dbus_string_get_length(s) (((DBusString*)(s))->dummy2)  #define _dbus_string_set_byte(s, i, b) ((((unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) = (unsigned char) (b))  #define _dbus_string_get_byte(s, i) (((const unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) @@ -71,7 +72,9 @@ dbus_bool_t   _dbus_string_init_preallocated     (DBusString        *str,                                                    int                allocate_size);  void          _dbus_string_free                  (DBusString        *str);  void          _dbus_string_lock                  (DBusString        *str); +#ifndef _dbus_string_get_data  char*         _dbus_string_get_data              (DBusString        *str); +#endif /* _dbus_string_get_data */  #ifndef _dbus_string_get_const_data  const char*   _dbus_string_get_const_data        (const DBusString  *str);  #endif /* _dbus_string_get_const_data */ @@ -205,11 +208,6 @@ dbus_bool_t   _dbus_string_parse_double          (const DBusString  *str,                                                    int                start,                                                    double            *value,                                                    int               *end_return); -dbus_bool_t   _dbus_string_parse_basic_type      (const DBusString  *str, -						  char               type, -                                                  int                start, -                                                  void              *value, -                                                  int               *end_return);  dbus_bool_t   _dbus_string_find                  (const DBusString  *str,                                                    int                start,                                                    const char        *substr, diff --git a/dbus/dbus-sysdeps-util.c b/dbus/dbus-sysdeps-util.c new file mode 100644 index 00000000..52298f81 --- /dev/null +++ b/dbus/dbus-sysdeps-util.c @@ -0,0 +1,871 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus + *  + * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * 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-sysdeps.h" +#include "dbus-internals.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#define DBUS_USERDB_INCLUDES_PRIVATE 1 +#include "dbus-userdb.h" +#include "dbus-test.h" + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <grp.h> +#include <sys/socket.h> +#include <dirent.h> +#include <sys/un.h> + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +/** + * Does the chdir, fork, setsid, etc. to become a daemon process. + * + * @param pidfile #NULL, or pidfile to create + * @param print_pid_fd file descriptor to print pid to, or -1 for none + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_become_daemon (const DBusString *pidfile, +		     int               print_pid_fd, +                     DBusError        *error) +{ +  const char *s; +  pid_t child_pid; +  int dev_null_fd; + +  _dbus_verbose ("Becoming a daemon...\n"); + +  _dbus_verbose ("chdir to /\n"); +  if (chdir ("/") < 0) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Could not chdir() to root directory"); +      return FALSE; +    } + +  _dbus_verbose ("forking...\n"); +  switch ((child_pid = fork ())) +    { +    case -1: +      _dbus_verbose ("fork failed\n"); +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to fork daemon: %s", _dbus_strerror (errno)); +      return FALSE; +      break; + +    case 0: +      _dbus_verbose ("in child, closing std file descriptors\n"); + +      /* silently ignore failures here, if someone +       * doesn't have /dev/null we may as well try +       * to continue anyhow +       */ +       +      dev_null_fd = open ("/dev/null", O_RDWR); +      if (dev_null_fd >= 0) +        { +          dup2 (dev_null_fd, 0); +          dup2 (dev_null_fd, 1); +           +          s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); +          if (s == NULL || *s == '\0') +            dup2 (dev_null_fd, 2); +          else +            _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); +        } + +      /* Get a predictable umask */ +      _dbus_verbose ("setting umask\n"); +      umask (022); +      break; + +    default: +      if (pidfile) +        { +          _dbus_verbose ("parent writing pid file\n"); +          if (!_dbus_write_pid_file (pidfile, +                                     child_pid, +                                     error)) +            { +              _dbus_verbose ("pid file write failed, killing child\n"); +              kill (child_pid, SIGTERM); +              return FALSE; +            } +        } + +      /* Write PID if requested */ +      if (print_pid_fd >= 0) +	{ +	  DBusString pid; +	  int bytes; +	   +	  if (!_dbus_string_init (&pid)) +	    { +	      _DBUS_SET_OOM (error); +              kill (child_pid, SIGTERM); +	      return FALSE; +	    } +	   +	  if (!_dbus_string_append_int (&pid, _dbus_getpid ()) || +	      !_dbus_string_append (&pid, "\n")) +	    { +	      _dbus_string_free (&pid); +	      _DBUS_SET_OOM (error); +              kill (child_pid, SIGTERM); +	      return FALSE; +	    } +	   +	  bytes = _dbus_string_get_length (&pid); +	  if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes) +	    { +	      dbus_set_error (error, DBUS_ERROR_FAILED, +			      "Printing message bus PID: %s\n", +			      _dbus_strerror (errno)); +	      _dbus_string_free (&pid); +              kill (child_pid, SIGTERM); +	      return FALSE; +	    } +	   +	  _dbus_string_free (&pid); +	} +      _dbus_verbose ("parent exiting\n"); +      _exit (0); +      break; +    } + +  _dbus_verbose ("calling setsid()\n"); +  if (setsid () == -1) +    _dbus_assert_not_reached ("setsid() failed"); +   +  return TRUE; +} + + +/** + * Creates a file containing the process ID. + * + * @param filename the filename to write to + * @param pid our process ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_write_pid_file (const DBusString *filename, +                      unsigned long     pid, +		      DBusError        *error) +{ +  const char *cfilename; +  int fd; +  FILE *f; + +  cfilename = _dbus_string_get_const_data (filename); +   +  fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); +   +  if (fd < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to open \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  if ((f = fdopen (fd, "w")) == NULL) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); +      close (fd); +      return FALSE; +    } +   +  if (fprintf (f, "%lu\n", pid) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to write to \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  if (fclose (f) == EOF) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to close \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); +      return FALSE; +    } +   +  return TRUE; +} + + +/** + * Changes the user and group the bus is running as. + * + * @param uid the new user ID + * @param gid the new group ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_identity  (dbus_uid_t     uid, +                        dbus_gid_t     gid, +                        DBusError     *error) +{ +  /* setgroups() only works if we are a privileged process, +   * so we don't return error on failure; the only possible +   * failure is that we don't have perms to do it. +   * FIXME not sure this is right, maybe if setuid() +   * is going to work then setgroups() should also work. +   */ +  if (setgroups (0, NULL) < 0) +    _dbus_warn ("Failed to drop supplementary groups: %s\n", +                _dbus_strerror (errno)); +   +  /* Set GID first, or the setuid may remove our permission +   * to change the GID +   */ +  if (setgid (gid) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to set GID to %lu: %s", gid, +                      _dbus_strerror (errno)); +      return FALSE; +    } +   +  if (setuid (uid) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to set UID to %lu: %s", uid, +                      _dbus_strerror (errno)); +      return FALSE; +    } +   +  return TRUE; +} + +/** Installs a UNIX signal handler + * + * @param sig the signal to handle + * @param handler the handler + */ +void +_dbus_set_signal_handler (int               sig, +                          DBusSignalHandler handler) +{ +  struct sigaction act; +  sigset_t empty_mask; +   +  sigemptyset (&empty_mask); +  act.sa_handler = handler; +  act.sa_mask    = empty_mask; +  act.sa_flags   = 0; +  sigaction (sig,  &act, 0); +} + + +/** + * Removes a directory; Directory must be empty + *  + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_delete_directory (const DBusString *filename, +			DBusError        *error) +{ +  const char *filename_c; +   +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (rmdir (filename_c) != 0) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +		      "Failed to remove directory %s: %s\n", +		      filename_c, _dbus_strerror (errno)); +      return FALSE; +    } +   +  return TRUE; +} + +/** Checks if a file exists +* +* @param file full path to the file +* @returns #TRUE if file exists +*/ +dbus_bool_t  +_dbus_file_exists (const char *file) +{ +  return (access (file, F_OK) == 0); +} + +/** Checks if user is at the console +* +* @param username user to check +* @param error return location for errors +* @returns #TRUE is the user is at the consolei and there are no errors +*/ +dbus_bool_t  +_dbus_user_at_console (const char *username, +                       DBusError  *error) +{ + +  DBusString f; +  dbus_bool_t result; + +  result = FALSE; +  if (!_dbus_string_init (&f)) +    { +      _DBUS_SET_OOM (error); +      return FALSE; +    } + +  if (!_dbus_string_append (&f, DBUS_CONSOLE_DIR)) +    { +      _DBUS_SET_OOM (error); +      goto out; +    } + + +  if (!_dbus_string_append (&f, username)) +    { +      _DBUS_SET_OOM (error); +      goto out; +    } + +  result = _dbus_file_exists (_dbus_string_get_const_data (&f)); + + out: +  _dbus_string_free (&f); + +  return result; +} + + +/** + * Checks whether the filename is an absolute path + * + * @param filename the filename + * @returns #TRUE if an absolute path + */ +dbus_bool_t +_dbus_path_is_absolute (const DBusString *filename) +{ +  if (_dbus_string_get_length (filename) > 0) +    return _dbus_string_get_byte (filename, 0) == '/'; +  else +    return FALSE; +} + +/** + * stat() wrapper. + * + * @param filename the filename to stat + * @param statbuf the stat info to fill in + * @param error return location for error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_stat (const DBusString *filename, +            DBusStat         *statbuf, +            DBusError        *error) +{ +  const char *filename_c; +  struct stat sb; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  filename_c = _dbus_string_get_const_data (filename); + +  if (stat (filename_c, &sb) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "%s", _dbus_strerror (errno)); +      return FALSE; +    } + +  statbuf->mode = sb.st_mode; +  statbuf->nlink = sb.st_nlink; +  statbuf->uid = sb.st_uid; +  statbuf->gid = sb.st_gid; +  statbuf->size = sb.st_size; +  statbuf->atime = sb.st_atime; +  statbuf->mtime = sb.st_mtime; +  statbuf->ctime = sb.st_ctime; + +  return TRUE; +} + + +/** + * Internals of directory iterator + */ +struct DBusDirIter +{ +  DIR *d; /**< The DIR* from opendir() */ +   +}; + +/** + * Open a directory to iterate over. + * + * @param filename the directory name + * @param error exception return object or #NULL + * @returns new iterator, or #NULL on error + */ +DBusDirIter* +_dbus_directory_open (const DBusString *filename, +                      DBusError        *error) +{ +  DIR *d; +  DBusDirIter *iter; +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  filename_c = _dbus_string_get_const_data (filename); + +  d = opendir (filename_c); +  if (d == NULL) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to read directory \"%s\": %s", +                      filename_c, +                      _dbus_strerror (errno)); +      return NULL; +    } +  iter = dbus_new0 (DBusDirIter, 1); +  if (iter == NULL) +    { +      closedir (d); +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, +                      "Could not allocate memory for directory iterator"); +      return NULL; +    } + +  iter->d = d; + +  return iter; +} + +/** + * Get next file in the directory. Will not return "." or ".."  on + * UNIX. If an error occurs, the contents of "filename" are + * undefined. The error is never set if the function succeeds. + * + * @todo for thread safety, I think we have to use + * readdir_r(). (GLib has the same issue, should file a bug.) + * + * @param iter the iterator + * @param filename string to be set to the next file in the dir + * @param error return location for error + * @returns #TRUE if filename was filled in with a new filename + */ +dbus_bool_t +_dbus_directory_get_next_file (DBusDirIter      *iter, +                               DBusString       *filename, +                               DBusError        *error) +{ +  struct dirent *ent; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   + again: +  errno = 0; +  ent = readdir (iter->d); +  if (ent == NULL) +    { +      if (errno != 0) +        dbus_set_error (error, +                        _dbus_error_from_errno (errno), +                        "%s", _dbus_strerror (errno)); +      return FALSE; +    } +  else if (ent->d_name[0] == '.' && +           (ent->d_name[1] == '\0' || +            (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) +    goto again; +  else +    { +      _dbus_string_set_length (filename, 0); +      if (!_dbus_string_append (filename, ent->d_name)) +        { +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, +                          "No memory to read directory entry"); +          return FALSE; +        } +      else +        return TRUE; +    } +} + +/** + * Closes a directory iteration. + */ +void +_dbus_directory_close (DBusDirIter *iter) +{ +  closedir (iter->d); +  dbus_free (iter); +} + +static dbus_bool_t +fill_user_info_from_group (struct group  *g, +                           DBusGroupInfo *info, +                           DBusError     *error) +{ +  _dbus_assert (g->gr_name != NULL); +   +  info->gid = g->gr_gid; +  info->groupname = _dbus_strdup (g->gr_name); + +  /* info->members = dbus_strdupv (g->gr_mem) */ +   +  if (info->groupname == NULL) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      return FALSE; +    } + +  return TRUE; +} + +static dbus_bool_t +fill_group_info (DBusGroupInfo    *info, +                 dbus_gid_t        gid, +                 const DBusString *groupname, +                 DBusError        *error) +{ +  const char *group_c_str; + +  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); +  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); + +  if (groupname) +    group_c_str = _dbus_string_get_const_data (groupname); +  else +    group_c_str = NULL; +   +  /* For now assuming that the getgrnam() and getgrgid() flavors +   * always correspond to the pwnam flavors, if not we have +   * to add more configure checks. +   */ +   +#if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R) +  { +    struct group *g; +    int result; +    char buf[1024]; +    struct group g_str; + +    g = NULL; +#ifdef HAVE_POSIX_GETPWNAME_R + +    if (group_c_str) +      result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), +                           &g); +    else +      result = getgrgid_r (gid, &g_str, buf, sizeof (buf), +                           &g); +#else +    p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf)); +    result = 0; +#endif /* !HAVE_POSIX_GETPWNAME_R */ +    if (result == 0 && g == &g_str) +      { +        return fill_user_info_from_group (g, info, error); +      } +    else +      { +        dbus_set_error (error, _dbus_error_from_errno (errno), +                        "Group %s unknown or failed to look it up\n", +                        group_c_str ? group_c_str : "???"); +        return FALSE; +      } +  } +#else /* ! HAVE_GETPWNAM_R */ +  { +    /* I guess we're screwed on thread safety here */ +    struct group *g; + +    g = getgrnam (group_c_str); + +    if (g != NULL) +      { +        return fill_user_info_from_group (g, info, error); +      } +    else +      { +        dbus_set_error (error, _dbus_error_from_errno (errno), +                        "Group %s unknown or failed to look it up\n", +                        group_c_str ? group_c_str : "???"); +        return FALSE; +      } +  } +#endif  /* ! HAVE_GETPWNAM_R */ +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group name. + * + * @param info the group info struct + * @param groupname name of group + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill (DBusGroupInfo    *info, +                       const DBusString *groupname, +                       DBusError        *error) +{ +  return fill_group_info (info, DBUS_GID_UNSET, +                          groupname, error); + +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group ID. + * + * @param info the group info struct + * @param gid group ID + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill_gid (DBusGroupInfo *info, +                           dbus_gid_t     gid, +                           DBusError     *error) +{ +  return fill_group_info (info, gid, NULL, error); +} + +/** + * Frees the members of info (but not info itself). + * + * @param info the group info + */ +void +_dbus_group_info_free (DBusGroupInfo    *info) +{ +  dbus_free (info->groupname); +} + +/** @} */ /* End of DBusInternalsUtils functions */ + +/** + * @addtogroup DBusString + * + * @{ + */ +/** + * Get the directory name from a complete filename + * @param filename the filename + * @param dirname string to append directory name to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_get_dirname  (const DBusString *filename, +                           DBusString       *dirname) +{ +  int sep; +   +  _dbus_assert (filename != dirname); +  _dbus_assert (filename != NULL); +  _dbus_assert (dirname != NULL); + +  /* Ignore any separators on the end */ +  sep = _dbus_string_get_length (filename); +  if (sep == 0) +    return _dbus_string_append (dirname, "."); /* empty string passed in */ +     +  while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') +    --sep; + +  _dbus_assert (sep >= 0); +   +  if (sep == 0) +    return _dbus_string_append (dirname, "/"); +   +  /* Now find the previous separator */ +  _dbus_string_find_byte_backward (filename, sep, '/', &sep); +  if (sep < 0) +    return _dbus_string_append (dirname, "."); +   +  /* skip multiple separators */ +  while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') +    --sep; + +  _dbus_assert (sep >= 0); +   +  if (sep == 0 && +      _dbus_string_get_byte (filename, 0) == '/') +    return _dbus_string_append (dirname, "/"); +  else +    return _dbus_string_copy_len (filename, 0, sep - 0, +                                  dirname, _dbus_string_get_length (dirname)); +} +/** @} */ /* DBusString stuff */ + + +#ifdef DBUS_BUILD_TESTS +#include <stdlib.h> +static void +check_dirname (const char *filename, +               const char *dirname) +{ +  DBusString f, d; +   +  _dbus_string_init_const (&f, filename); + +  if (!_dbus_string_init (&d)) +    _dbus_assert_not_reached ("no memory"); + +  if (!_dbus_string_get_dirname (&f, &d)) +    _dbus_assert_not_reached ("no memory"); + +  if (!_dbus_string_equal_c_str (&d, dirname)) +    { +      _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n", +                  filename, +                  _dbus_string_get_const_data (&d), +                  dirname); +      exit (1); +    } + +  _dbus_string_free (&d); +} + +static void +check_path_absolute (const char *path, +                     dbus_bool_t expected) +{ +  DBusString p; + +  _dbus_string_init_const (&p, path); + +  if (_dbus_path_is_absolute (&p) != expected) +    { +      _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n", +                  path, expected, _dbus_path_is_absolute (&p)); +      exit (1); +    } +} + +/** + * Unit test for dbus-sysdeps.c. + *  + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_sysdeps_test (void) +{ +  DBusString str; +  double val; +  int pos; +   +  check_dirname ("foo", "."); +  check_dirname ("foo/bar", "foo"); +  check_dirname ("foo//bar", "foo"); +  check_dirname ("foo///bar", "foo"); +  check_dirname ("foo/bar/", "foo"); +  check_dirname ("foo//bar/", "foo"); +  check_dirname ("foo///bar/", "foo"); +  check_dirname ("foo/bar//", "foo"); +  check_dirname ("foo//bar////", "foo"); +  check_dirname ("foo///bar///////", "foo"); +  check_dirname ("/foo", "/"); +  check_dirname ("////foo", "/"); +  check_dirname ("/foo/bar", "/foo"); +  check_dirname ("/foo//bar", "/foo"); +  check_dirname ("/foo///bar", "/foo"); +  check_dirname ("/", "/"); +  check_dirname ("///", "/"); +  check_dirname ("", ".");   + + +  _dbus_string_init_const (&str, "3.5"); +  if (!_dbus_string_parse_double (&str, +				  0, &val, &pos)) +    { +      _dbus_warn ("Failed to parse double"); +      exit (1); +    } +  if (ABS(3.5 - val) > 1e-6) +    { +      _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val); +      exit (1); +    } +  if (pos != 3) +    { +      _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos); +      exit (1); +    } + +  _dbus_string_init_const (&str, "0xff"); +  if (!_dbus_string_parse_double (&str, +				  0, &val, &pos)) +    { +      _dbus_warn ("Failed to parse double"); +      exit (1); +    } +  if (ABS (0xff - val) > 1e-6) +    { +      _dbus_warn ("Failed to parse 0xff correctly, got: %f\n", val); +      exit (1); +    } +  if (pos != 4) +    { +      _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos); +      exit (1); +    } +   +  check_path_absolute ("/", TRUE); +  check_path_absolute ("/foo", TRUE); +  check_path_absolute ("", FALSE); +  check_path_absolute ("foo", FALSE); +  check_path_absolute ("foo/bar", FALSE); +   +  return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 049c63ab..d951a8d6 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1628,149 +1628,6 @@ _dbus_user_info_free (DBusUserInfo *info)    dbus_free (info->homedir);  } -static dbus_bool_t -fill_user_info_from_group (struct group  *g, -                           DBusGroupInfo *info, -                           DBusError     *error) -{ -  _dbus_assert (g->gr_name != NULL); -   -  info->gid = g->gr_gid; -  info->groupname = _dbus_strdup (g->gr_name); - -  /* info->members = dbus_strdupv (g->gr_mem) */ -   -  if (info->groupname == NULL) -    { -      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -      return FALSE; -    } - -  return TRUE; -} - -static dbus_bool_t -fill_group_info (DBusGroupInfo    *info, -                 dbus_gid_t        gid, -                 const DBusString *groupname, -                 DBusError        *error) -{ -  const char *group_c_str; - -  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); -  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); - -  if (groupname) -    group_c_str = _dbus_string_get_const_data (groupname); -  else -    group_c_str = NULL; -   -  /* For now assuming that the getgrnam() and getgrgid() flavors -   * always correspond to the pwnam flavors, if not we have -   * to add more configure checks. -   */ -   -#if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R) -  { -    struct group *g; -    int result; -    char buf[1024]; -    struct group g_str; - -    g = NULL; -#ifdef HAVE_POSIX_GETPWNAME_R - -    if (group_c_str) -      result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), -                           &g); -    else -      result = getgrgid_r (gid, &g_str, buf, sizeof (buf), -                           &g); -#else -    p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf)); -    result = 0; -#endif /* !HAVE_POSIX_GETPWNAME_R */ -    if (result == 0 && g == &g_str) -      { -        return fill_user_info_from_group (g, info, error); -      } -    else -      { -        dbus_set_error (error, _dbus_error_from_errno (errno), -                        "Group %s unknown or failed to look it up\n", -                        group_c_str ? group_c_str : "???"); -        return FALSE; -      } -  } -#else /* ! HAVE_GETPWNAM_R */ -  { -    /* I guess we're screwed on thread safety here */ -    struct group *g; - -    g = getgrnam (group_c_str); - -    if (g != NULL) -      { -        return fill_user_info_from_group (g, info, error); -      } -    else -      { -        dbus_set_error (error, _dbus_error_from_errno (errno), -                        "Group %s unknown or failed to look it up\n", -                        group_c_str ? group_c_str : "???"); -        return FALSE; -      } -  } -#endif  /* ! HAVE_GETPWNAM_R */ -} - -/** - * Initializes the given DBusGroupInfo struct - * with information about the given group name. - * - * @param info the group info struct - * @param groupname name of group - * @param error the error return - * @returns #FALSE if error is set - */ -dbus_bool_t -_dbus_group_info_fill (DBusGroupInfo    *info, -                       const DBusString *groupname, -                       DBusError        *error) -{ -  return fill_group_info (info, DBUS_GID_UNSET, -                          groupname, error); - -} - -/** - * Initializes the given DBusGroupInfo struct - * with information about the given group ID. - * - * @param info the group info struct - * @param gid group ID - * @param error the error return - * @returns #FALSE if error is set - */ -dbus_bool_t -_dbus_group_info_fill_gid (DBusGroupInfo *info, -                           dbus_gid_t     gid, -                           DBusError     *error) -{ -  return fill_group_info (info, gid, NULL, error); -} - -/** - * Frees the members of info (but not info itself). - * - * @param info the group info - */ -void -_dbus_group_info_free (DBusGroupInfo    *info) -{ -  dbus_free (info->groupname); -} -  /**   * Sets fields in DBusCredentials to DBUS_PID_UNSET,   * DBUS_UID_UNSET, DBUS_GID_UNSET. @@ -1849,6 +1706,7 @@ _dbus_getuid (void)    return getuid ();  } +#ifdef DBUS_BUILD_TESTS  /** Gets our GID   * @returns process GID   */ @@ -1857,6 +1715,7 @@ _dbus_getgid (void)  {    return getgid ();  } +#endif  _DBUS_DEFINE_GLOBAL_LOCK (atomic); @@ -2467,118 +2326,6 @@ _dbus_concat_dir_and_file (DBusString       *dir,                              _dbus_string_get_length (dir));  } -/** - * Internals of directory iterator - */ -struct DBusDirIter -{ -  DIR *d; /**< The DIR* from opendir() */ -   -}; - -/** - * Open a directory to iterate over. - * - * @param filename the directory name - * @param error exception return object or #NULL - * @returns new iterator, or #NULL on error - */ -DBusDirIter* -_dbus_directory_open (const DBusString *filename, -                      DBusError        *error) -{ -  DIR *d; -  DBusDirIter *iter; -  const char *filename_c; - -  _DBUS_ASSERT_ERROR_IS_CLEAR (error); -   -  filename_c = _dbus_string_get_const_data (filename); - -  d = opendir (filename_c); -  if (d == NULL) -    { -      dbus_set_error (error, _dbus_error_from_errno (errno), -                      "Failed to read directory \"%s\": %s", -                      filename_c, -                      _dbus_strerror (errno)); -      return NULL; -    } -  iter = dbus_new0 (DBusDirIter, 1); -  if (iter == NULL) -    { -      closedir (d); -      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, -                      "Could not allocate memory for directory iterator"); -      return NULL; -    } - -  iter->d = d; - -  return iter; -} - -/** - * Get next file in the directory. Will not return "." or ".."  on - * UNIX. If an error occurs, the contents of "filename" are - * undefined. The error is never set if the function succeeds. - * - * @todo for thread safety, I think we have to use - * readdir_r(). (GLib has the same issue, should file a bug.) - * - * @param iter the iterator - * @param filename string to be set to the next file in the dir - * @param error return location for error - * @returns #TRUE if filename was filled in with a new filename - */ -dbus_bool_t -_dbus_directory_get_next_file (DBusDirIter      *iter, -                               DBusString       *filename, -                               DBusError        *error) -{ -  struct dirent *ent; - -  _DBUS_ASSERT_ERROR_IS_CLEAR (error); -   - again: -  errno = 0; -  ent = readdir (iter->d); -  if (ent == NULL) -    { -      if (errno != 0) -        dbus_set_error (error, -                        _dbus_error_from_errno (errno), -                        "%s", _dbus_strerror (errno)); -      return FALSE; -    } -  else if (ent->d_name[0] == '.' && -           (ent->d_name[1] == '\0' || -            (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) -    goto again; -  else -    { -      _dbus_string_set_length (filename, 0); -      if (!_dbus_string_append (filename, ent->d_name)) -        { -          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, -                          "No memory to read directory entry"); -          return FALSE; -        } -      else -        return TRUE; -    } -} - -/** - * Closes a directory iteration. - */ -void -_dbus_directory_close (DBusDirIter *iter) -{ -  closedir (iter->d); -  dbus_free (iter); -} -  static dbus_bool_t  pseudorandom_generate_random_bytes (DBusString *str,                                      int         n_bytes) @@ -2859,62 +2606,6 @@ _dbus_exit (int code)  }  /** - * Creates a full-duplex pipe (as in socketpair()). - * Sets both ends of the pipe nonblocking. - * - * @param fd1 return location for one end - * @param fd2 return location for the other end - * @param blocking #TRUE if pipe should be blocking - * @param error error return - * @returns #FALSE on failure (if error is set) - */ -dbus_bool_t -_dbus_full_duplex_pipe (int        *fd1, -                        int        *fd2, -                        dbus_bool_t blocking, -                        DBusError  *error) -{ -#ifdef HAVE_SOCKETPAIR -  int fds[2]; - -  _DBUS_ASSERT_ERROR_IS_CLEAR (error); -   -  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) -    { -      dbus_set_error (error, _dbus_error_from_errno (errno), -                      "Could not create full-duplex pipe"); -      return FALSE; -    } - -  if (!blocking && -      (!_dbus_set_fd_nonblocking (fds[0], NULL) || -       !_dbus_set_fd_nonblocking (fds[1], NULL))) -    { -      dbus_set_error (error, _dbus_error_from_errno (errno), -                      "Could not set full-duplex pipe nonblocking"); -       -      close (fds[0]); -      close (fds[1]); -       -      return FALSE; -    } -   -  *fd1 = fds[0]; -  *fd2 = fds[1]; - -  _dbus_verbose ("full-duplex pipe %d <-> %d\n", -                 *fd1, *fd2); -   -  return TRUE;   -#else -  _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n"); -  dbus_set_error (error, DBUS_ERROR_FAILED, -                  "_dbus_full_duplex_pipe() not implemented on this OS"); -  return FALSE; -#endif -} - -/**   * Closes a file descriptor.   *   * @param fd the file descriptor @@ -3055,6 +2746,67 @@ _dbus_parse_uid (const DBusString      *uid_str,    return TRUE;  } +/** + * Creates a full-duplex pipe (as in socketpair()). + * Sets both ends of the pipe nonblocking. + * + * @todo libdbus only uses this for the debug-pipe server, so in + * principle it could be in dbus-sysdeps-util.c, except that + * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the + * debug-pipe server is used. + *  + * @param fd1 return location for one end + * @param fd2 return location for the other end + * @param blocking #TRUE if pipe should be blocking + * @param error error return + * @returns #FALSE on failure (if error is set) + */ +dbus_bool_t +_dbus_full_duplex_pipe (int        *fd1, +                        int        *fd2, +                        dbus_bool_t blocking, +                        DBusError  *error) +{ +#ifdef HAVE_SOCKETPAIR +  int fds[2]; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not create full-duplex pipe"); +      return FALSE; +    } + +  if (!blocking && +      (!_dbus_set_fd_nonblocking (fds[0], NULL) || +       !_dbus_set_fd_nonblocking (fds[1], NULL))) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not set full-duplex pipe nonblocking"); +       +      close (fds[0]); +      close (fds[1]); +       +      return FALSE; +    } +   +  *fd1 = fds[0]; +  *fd2 = fds[1]; + +  _dbus_verbose ("full-duplex pipe %d <-> %d\n", +                 *fd1, *fd2); +   +  return TRUE;   +#else +  _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n"); +  dbus_set_error (error, DBUS_ERROR_FAILED, +                  "_dbus_full_duplex_pipe() not implemented on this OS"); +  return FALSE; +#endif +} +  /** @} end of sysdeps */  /* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c index 20287f91..10226007 100644 --- a/dbus/dbus-userdb-util.c +++ b/dbus/dbus-userdb-util.c @@ -32,7 +32,6 @@   * @{   */ -  /**   * Checks to see if the UID sent in is the console user   * diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c index ff583204..85ee1b67 100644 --- a/dbus/dbus-userdb.c +++ b/dbus/dbus-userdb.c @@ -442,6 +442,7 @@ _dbus_user_database_new (void)    return NULL;  } +#ifdef DBUS_BUILD_TESTS  /**   * Increments refcount of user database.   * @param db the database @@ -456,6 +457,7 @@ _dbus_user_database_ref (DBusUserDatabase  *db)    return db;  } +#endif /* DBUS_BUILD_TESTS */  /**   * Decrements refcount of user database. diff --git a/test/unused-code-gc.py b/test/unused-code-gc.py index 7bc1930b..a58597f7 100755 --- a/test/unused-code-gc.py +++ b/test/unused-code-gc.py @@ -230,6 +230,8 @@ trace 'reachable' through hardcoded function calls, if a function is  called only through a vtable, it won't be marked reachable (and  neither will its children in the call graph). +Also, the sizes mentioned are more or less completely bogus. +  """      print "The following are hardcoded in as vtable roots: %s" % vtable_roots | 
