dbus/dbus Makefile.am, 1.62, 1.63 dbus-auth-util.c, NONE, 1.1 dbus-auth.c, 1.39, 1.40 dbus-hash.c, 1.18, 1.19 dbus-internals.c, 1.40, 1.41 dbus-internals.h, 1.49, 1.50 dbus-list.c, 1.19, 1.20 dbus-marshal-basic.c, 1.17, 1.18 dbus-marshal-basic.h, 1.14, 1.15 dbus-marshal-recursive-util.c, NONE, 1.1 dbus-marshal-recursive.c, 1.42, 1.43 dbus-message-builder.c, 1.26, 1.27 dbus-message-internal.h, 1.19, 1.20 dbus-message-private.h, NONE, 1.1 dbus-message-util.c, NONE, 1.1 dbus-message.c, 1.149, 1.150 dbus-string-private.h, 1.4, 1.5 dbus-string-util.c, NONE, 1.1 dbus-string.c, 1.63, 1.64 dbus-string.h, 1.36, 1.37 dbus-sysdeps-util.c, NONE, 1.1 dbus-sysdeps.c, 1.87, 1.88 dbus-userdb-util.c, 1.1, 1.2 dbus-userdb.c, 1.13, 1.14

Havoc Pennington hp@freedesktop.org
Sun Jan 16 19:53:42 PST 2005


Update of /cvs/dbus/dbus/dbus
In directory gabe:/tmp/cvs-serv15337/dbus

Modified Files:
	Makefile.am dbus-auth.c dbus-hash.c dbus-internals.c 
	dbus-internals.h dbus-list.c dbus-marshal-basic.c 
	dbus-marshal-basic.h dbus-marshal-recursive.c 
	dbus-message-builder.c dbus-message-internal.h dbus-message.c 
	dbus-string-private.h dbus-string.c dbus-string.h 
	dbus-sysdeps.c dbus-userdb-util.c dbus-userdb.c 
Added Files:
	dbus-auth-util.c dbus-marshal-recursive-util.c 
	dbus-message-private.h dbus-message-util.c dbus-string-util.c 
	dbus-sysdeps-util.c 
Log Message:
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



Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/dbus/Makefile.am,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -d -r1.62 -r1.63
--- Makefile.am	17 Jan 2005 01:20:02 -0000	1.62
+++ Makefile.am	17 Jan 2005 03:53:40 -0000	1.63
@@ -62,15 +62,16 @@
 	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 @@
 ### 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)			\

--- NEW FILE: dbus-auth-util.c ---
/* -*- 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 */

Index: dbus-auth.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-auth.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- dbus-auth.c	17 Jan 2005 01:20:02 -0000	1.39
+++ dbus-auth.c	17 Jan 2005 03:53:40 -0000	1.40
@@ -2392,139 +2392,4 @@
 
 /** @} */
 
-#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 */

Index: dbus-hash.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-hash.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- dbus-hash.c	10 Aug 2004 03:06:59 -0000	1.18
+++ dbus-hash.c	17 Jan 2005 03:53:40 -0000	1.19
@@ -231,13 +231,17 @@
                                                  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 @@
       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 @@
   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 @@
 
   return real->entry->key;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * A low-level but efficient interface for manipulating the hash
@@ -849,6 +857,7 @@
   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 @@
   
   return h;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /** Key comparison function */
 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
@@ -928,6 +938,7 @@
                                 preallocated);
 }
 
+#ifdef DBUS_BUILD_TESTS
 static int
 two_strings_cmp (const char *a,
                  const char *b)
@@ -945,7 +956,9 @@
 
   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 @@
                                 (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 @@
               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 @@
     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 @@
   else
     return NULL;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Looks up the value for a given integer in a hash table
@@ -1258,6 +1279,7 @@
     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 @@
   else
     return FALSE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Removes the hash entry for the given key. If no hash entry
@@ -1407,6 +1430,7 @@
   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 @@
 
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Creates a hash entry with the given key and value.

Index: dbus-internals.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-internals.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- dbus-internals.c	17 Jan 2005 00:16:28 -0000	1.40
+++ dbus-internals.c	17 Jan 2005 03:53:40 -0000	1.41
@@ -174,6 +174,8 @@
   va_end (args);
 }
 
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+
 static dbus_bool_t verbose_initted = FALSE;
 
 /**
@@ -238,6 +240,8 @@
   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 @@
   return FALSE;
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Returns a string describing the given name.
  *
@@ -387,6 +392,7 @@
       return "unknown";
     }
 }
+#endif /* DBUS_BUILD_TESTS */
 
 #ifndef DBUS_DISABLE_CHECKS
 /** String used in _dbus_return_if_fail macro */

Index: dbus-internals.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-internals.h,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -d -r1.49 -r1.50
--- dbus-internals.h	17 Jan 2005 00:16:28 -0000	1.49
+++ dbus-internals.h	17 Jan 2005 03:53:40 -0000	1.50
@@ -39,9 +39,6 @@
 
 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 @@
 #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

Index: dbus-list.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-list.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- dbus-list.c	10 Aug 2004 03:06:59 -0000	1.19
+++ dbus-list.c	17 Jan 2005 03:53:40 -0000	1.20
@@ -126,6 +126,7 @@
     }
 }
 
+#ifdef DBUS_BUILD_TESTS
 static void
 link_after (DBusList **list,
             DBusList  *after_this_link,
@@ -145,6 +146,7 @@
       link->next->prev = link;
     }
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /** @} */
 
@@ -313,6 +315,7 @@
   link_before (list, *list, link);
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Inserts data into the list before the given existing link.
  * 
@@ -341,7 +344,9 @@
   
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Inserts data into the list after the given existing link.
  * 
@@ -370,6 +375,7 @@
   
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Inserts a link into the list before the given existing link.
@@ -389,6 +395,7 @@
     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 @@
   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 @@
   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 @@
 
   return link;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Copies a list. This is a linear-time operation.  If there isn't

Index: dbus-marshal-basic.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-marshal-basic.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- dbus-marshal-basic.c	17 Jan 2005 00:16:28 -0000	1.17
+++ dbus-marshal-basic.c	17 Jan 2005 03:53:40 -0000	1.18
@@ -88,21 +88,6 @@
   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 @@
 }
 #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,

Index: dbus-marshal-basic.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-marshal-basic.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- dbus-marshal-basic.h	16 Jan 2005 15:51:55 -0000	1.14
+++ dbus-marshal-basic.h	17 Jan 2005 03:53:40 -0000	1.15
@@ -152,11 +152,6 @@
      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);

--- NEW FILE: dbus-marshal-recursive-util.c ---
/* -*- 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 = &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 */

Index: dbus-marshal-recursive.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-marshal-recursive.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- dbus-marshal-recursive.c	17 Jan 2005 00:16:28 -0000	1.42
+++ dbus-marshal-recursive.c	17 Jan 2005 03:53:40 -0000	1.43
@@ -2710,2925 +2710,4 @@
 
 /** @} */ /* 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 = &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 */

Index: dbus-message-builder.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message-builder.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- dbus-message-builder.c	15 Jan 2005 07:15:38 -0000	1.26
+++ dbus-message-builder.c	17 Jan 2005 03:53:40 -0000	1.27
@@ -335,6 +335,115 @@
   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,

Index: dbus-message-internal.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message-internal.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- dbus-message-internal.h	15 Jan 2005 07:15:38 -0000	1.19
+++ dbus-message-internal.h	17 Jan 2005 03:53:40 -0000	1.20
@@ -71,4 +71,4 @@
 
 DBUS_END_DECLS
 
-#endif /* DBUS_MESSAGE_H */
+#endif /* DBUS_MESSAGE_INTERNAL_H */

--- NEW FILE: dbus-message-private.h ---
/* -*- 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 */

--- NEW FILE: dbus-message-util.c ---
/* -*- 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 (&copy->header.data));

  _dbus_assert (_dbus_string_get_length (&message->body) ==
                _dbus_string_get_length (&copy->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 */

Index: dbus-message.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message.c,v
retrieving revision 1.149
retrieving revision 1.150
diff -u -d -r1.149 -r1.150
--- dbus-message.c	17 Jan 2005 00:16:28 -0000	1.149
+++ dbus-message.c	17 Jan 2005 03:53:40 -0000	1.150
@@ -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_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_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 @@
  * @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 @@
 
           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 @@
               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 @@
               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 @@
  *
  * @{
  */
-/**
- * @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 @@
 }
 
 /** @} */
-#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 (&copy->header.data));
-
-  _dbus_assert (_dbus_string_get_length (&message->body) ==
-                _dbus_string_get_length (&copy->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 */

Index: dbus-string-private.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-string-private.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-string-private.h	9 Sep 2004 10:20:17 -0000	1.4
+++ dbus-string-private.h	17 Jan 2005 03:53:40 -0000	1.5
@@ -53,6 +53,62 @@
   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 */

--- NEW FILE: dbus-string-util.c ---
/* -*- 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 */

Index: dbus-string.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-string.c,v
retrieving revision 1.63
retrieving revision 1.64
diff -u -d -r1.63 -r1.64
--- dbus-string.c	16 Jan 2005 15:51:55 -0000	1.63
+++ dbus-string.c	17 Jan 2005 03:53:40 -0000	1.64
@@ -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 @@
   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 @@
   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 @@
 
   real->max_length = max_length;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Initializes a constant string. The value parameter is not copied
@@ -286,7 +233,7 @@
   
   _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 @@
   /* 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 @@
   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 @@
   
   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 @@
   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_free (&dest);
   return TRUE;
 }
-
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Copies the data from the string into a char*
@@ -758,6 +708,7 @@
   return TRUE;
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Copies a segment of the string into a char*
  *
@@ -802,30 +753,7 @@
   _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 @@
   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 @@
 } 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 @@
 
   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 @@
 
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Inserts 4 bytes aligned on a 4 byte boundary
@@ -1299,6 +1232,7 @@
   return TRUE;
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Appends a single Unicode character, encoding the character
  * in UTF-8 format.
@@ -1369,6 +1303,7 @@
 
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 static void
 delete (DBusRealString *real,
@@ -1730,6 +1665,7 @@
      ((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 @@
   if (end_return)
     *end_return = start + len;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Finds the given substring in the string,
@@ -1877,43 +1814,6 @@
 }
 
 /**
- * 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 @@
 }
 
 /**
- * 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 @@
   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 (str, 0, i);
 }
+#endif
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Deletes any leading blanks in the string
  *
@@ -2124,6 +1990,7 @@
   if (i > 0)
     _dbus_string_delete (str, 0, i);
 }
+#endif
 
 /**
  * Tests two DBusString for equality.
@@ -2164,6 +2031,7 @@
   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 @@
 
   return TRUE;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Tests two sub-parts of two DBusString for equality.  The specified
@@ -2302,6 +2171,7 @@
   return TRUE;
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Checks whether a string starts with the given C string.
  *
@@ -2337,49 +2207,7 @@
   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 @@
 }
 /** @} */
 
-#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 */

Index: dbus-string.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-string.h,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- dbus-string.h	16 Jan 2005 02:23:56 -0000	1.36
+++ dbus-string.h	17 Jan 2005 03:53:40 -0000	1.37
@@ -54,6 +54,7 @@
  * 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 @@
                                                   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 @@
                                                   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,

--- NEW FILE: dbus-sysdeps-util.c ---
/* -*- 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 */

Index: dbus-sysdeps.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sysdeps.c,v
retrieving revision 1.87
retrieving revision 1.88
diff -u -d -r1.87 -r1.88
--- dbus-sysdeps.c	17 Jan 2005 01:20:02 -0000	1.87
+++ dbus-sysdeps.c	17 Jan 2005 03:53:40 -0000	1.88
@@ -1628,149 +1628,6 @@
   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 @@
   return getuid ();
 }
 
+#ifdef DBUS_BUILD_TESTS
 /** Gets our GID
  * @returns process GID
  */
@@ -1857,6 +1715,7 @@
 {
   return getgid ();
 }
+#endif
 
 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
 
@@ -2467,118 +2326,6 @@
                             _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 @@
 }
 
 /**
- * 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 @@
   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 */

Index: dbus-userdb-util.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-userdb-util.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dbus-userdb-util.c	17 Jan 2005 01:20:02 -0000	1.1
+++ dbus-userdb-util.c	17 Jan 2005 03:53:40 -0000	1.2
@@ -32,7 +32,6 @@
  * @{
  */
 
-
 /**
  * Checks to see if the UID sent in is the console user
  *

Index: dbus-userdb.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-userdb.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- dbus-userdb.c	17 Jan 2005 01:20:02 -0000	1.13
+++ dbus-userdb.c	17 Jan 2005 03:53:40 -0000	1.14
@@ -442,6 +442,7 @@
   return NULL;
 }
 
+#ifdef DBUS_BUILD_TESTS
 /**
  * Increments refcount of user database.
  * @param db the database
@@ -456,6 +457,7 @@
 
   return db;
 }
+#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Decrements refcount of user database.



More information about the dbus-commit mailing list