]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
2005-01-16 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 17 Jan 2005 03:53:40 +0000 (03:53 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 17 Jan 2005 03:53:40 +0000 (03:53 +0000)
        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

26 files changed:
ChangeLog
dbus/Makefile.am
dbus/dbus-auth-util.c [new file with mode: 0644]
dbus/dbus-auth.c
dbus/dbus-hash.c
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-list.c
dbus/dbus-marshal-basic.c
dbus/dbus-marshal-basic.h
dbus/dbus-marshal-recursive-util.c [new file with mode: 0644]
dbus/dbus-marshal-recursive.c
dbus/dbus-message-builder.c
dbus/dbus-message-internal.h
dbus/dbus-message-private.h [new file with mode: 0644]
dbus/dbus-message-util.c [new file with mode: 0644]
dbus/dbus-message.c
dbus/dbus-string-private.h
dbus/dbus-string-util.c [new file with mode: 0644]
dbus/dbus-string.c
dbus/dbus-string.h
dbus/dbus-sysdeps-util.c [new file with mode: 0644]
dbus/dbus-sysdeps.c
dbus/dbus-userdb-util.c
dbus/dbus-userdb.c
test/unused-code-gc.py

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