diff options
56 files changed, 6561 insertions, 9901 deletions
@@ -1,3 +1,62 @@ +2005-01-15  Havoc Pennington  <hp@redhat.com> + +	* Land the new message args API and type system. + +	This patch is huge, but the public API change is not  +	really large. The set of D-BUS types has changed somewhat,  +	and the arg "getters" are more geared toward language bindings; +	they don't make a copy, etc. + +	There are also some known issues. See these emails for details +	on this huge patch: +	http://lists.freedesktop.org/archives/dbus/2004-December/001836.html +        http://lists.freedesktop.org/archives/dbus/2005-January/001922.html +	 +	* dbus/dbus-marshal-*: all the new stuff + +	* dbus/dbus-message.c: basically rewritten + +	* dbus/dbus-memory.c (check_guards): with "guards" enabled, init +	freed blocks to be all non-nul bytes so using freed memory is less +	likely to work right + +	* dbus/dbus-internals.c (_dbus_test_oom_handling): add +	DBUS_FAIL_MALLOC=N environment variable, so you can do +	DBUS_FAIL_MALLOC=0 to skip the out-of-memory checking, or +	DBUS_FAIL_MALLOC=10 to make it really, really, really slow and +	thorough. + +	* qt/message.cpp: port to the new message args API +	(operator<<): use str.utf8() rather than str.unicode() +	(pretty sure this is right from the Qt docs?) + +	* glib/dbus-gvalue.c: port to the new message args API + +	* bus/dispatch.c, bus/driver.c: port to the new message args API + +	* dbus/dbus-string.c (_dbus_string_init_const_len): initialize the +	"locked" flag to TRUE and align_offset to 0; I guess we never +	looked at these anyhow, but seems cleaner. + +	* dbus/dbus-string.h (_DBUS_STRING_ALLOCATION_PADDING): +	move allocation padding macro to this header; use it to implement +	(_DBUS_STRING_STATIC): ability to declare a static string. + +	* dbus/dbus-message.c (_dbus_message_has_type_interface_member): +	change to return TRUE if the interface is not set. + +	* dbus/dbus-string.[hc]: move the D-BUS specific validation stuff +	to dbus-marshal-validate.[hc] + +	* dbus/dbus-marshal-basic.c (_dbus_type_to_string): move here from +	dbus-internals.c + +	* dbus/Makefile.am: cut over from dbus-marshal.[hc] +	to dbus-marshal-*.[hc] + +	* dbus/dbus-object-tree.c (_dbus_decompose_path): move this +	function here from dbus-marshal.c +  2005-01-12  Joe Shaw  <joeshaw@novell.com>  	* NEWS: Update for 0.23. @@ -127,6 +127,17 @@ dbus_realloc to fail if the number of bytes to be allocated is greater  than the specified number. This only works if D-BUS has been compiled with  --enable-tests. +DBUS_TEST_MALLOC_FAILURES=n +Many of the D-BUS tests will run over and over, once for each malloc +involved in the test. Each run will fail a different malloc, plus some +number of mallocs following that malloc (because a fair number of bugs +only happen if two or more mallocs fail in a row, e.g. error recovery +that itself involves malloc).  This env variable sets the number of +mallocs to fail. +Here's why you care: If set to 0, then the malloc checking is skipped, +which makes the test suite a heck of a lot faster. Just run with this +env variable unset before you commit. +  Tests  === diff --git a/bus/activation.c b/bus/activation.c index 9010b941..7461720a 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -93,6 +93,7 @@ typedef struct    unsigned int timeout_added : 1;  } BusPendingActivation; +#if 0  static BusServiceDirectory *  bus_service_directory_ref (BusServiceDirectory *dir)  { @@ -102,6 +103,7 @@ bus_service_directory_ref (BusServiceDirectory *dir)    return dir;  } +#endif  static void  bus_service_directory_unref (BusServiceDirectory *dir) @@ -909,15 +911,19 @@ bus_activation_service_created (BusActivation  *activation,  	  /* Only send activation replies to regular activation requests. */  	  if (!entry->auto_activation)  	    { +              dbus_uint32_t result; +                	      message = dbus_message_new_method_return (entry->activation_message);  	      if (!message)  		{  		  BUS_SET_OOM (error);  		  goto error;  		} -	       + +              result = DBUS_ACTIVATION_REPLY_ACTIVATED; +                	      if (!dbus_message_append_args (message, -					     DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED, +					     DBUS_TYPE_UINT32, &result,  					     DBUS_TYPE_INVALID))  		{  		  dbus_message_unref (message); @@ -1328,6 +1334,8 @@ bus_activation_activate_service (BusActivation  *activation,        _dbus_string_init_const (&service_str, service_name);        if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)          { +          dbus_uint32_t result; +                      _dbus_verbose ("Service \"%s\" is already active\n", service_name);            message = dbus_message_new_method_return (activation_message); @@ -1339,8 +1347,10 @@ bus_activation_activate_service (BusActivation  *activation,                return FALSE;              } +          result = DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE; +                      if (!dbus_message_append_args (message, -                                         DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,  +                                         DBUS_TYPE_UINT32, &result,                                           DBUS_TYPE_INVALID))              {                _dbus_verbose ("No memory to set args of reply to activate message\n"); diff --git a/bus/connection.c b/bus/connection.c index a16a22cd..140c7300 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -1398,6 +1398,7 @@ bus_pending_reply_send_no_reply (BusConnections  *connections,    DBusMessage *message;    DBusMessageIter iter;    dbus_bool_t retval; +  const char *errmsg;    retval = FALSE; @@ -1414,9 +1415,10 @@ bus_pending_reply_send_no_reply (BusConnections  *connections,    if (!dbus_message_set_error_name (message,                                      DBUS_ERROR_NO_REPLY))      goto out; -   + +  errmsg = "Message did not receive a reply (timeout by message bus)";    dbus_message_append_iter_init (message, &iter); -  if (!dbus_message_iter_append_string (&iter, "Message did not receive a reply (timeout by message bus)")) +  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg))      goto out;    if (!bus_transaction_send_from_driver (transaction, pending->will_get_reply, diff --git a/bus/dispatch.c b/bus/dispatch.c index e04d2895..4f7620b1 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -2,7 +2,7 @@  /* dispatch.c  Message dispatcher   *   * Copyright (C) 2003  CodeFactory AB - * Copyright (C) 2003, 2004  Red Hat, Inc. + * Copyright (C) 2003, 2004, 2005  Red Hat, Inc.   * Copyright (C) 2004  Imendio HB   *   * Licensed under the Academic Free License version 2.1 @@ -526,7 +526,7 @@ check_service_owner_changed_foreach (DBusConnection *connection,    CheckServiceOwnerChangedData *d = data;    DBusMessage *message;    DBusError error; -  char *service_name, *old_owner, *new_owner; +  const char *service_name, *old_owner, *new_owner;    if (d->expected_kind == SERVICE_CREATED         && connection == d->skip_connection) @@ -567,9 +567,6 @@ check_service_owner_changed_foreach (DBusConnection *connection,  	{  	  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))  	    { -              dbus_free (service_name); -              dbus_free (old_owner); -              dbus_free (new_owner);                dbus_error_free (&error);                _dbus_wait_for_memory ();                              goto reget_service_info_data; @@ -609,9 +606,6 @@ check_service_owner_changed_foreach (DBusConnection *connection,    d->failed = FALSE;   out: -  dbus_free (service_name); -  dbus_free (old_owner); -  dbus_free (new_owner);    dbus_error_free (&error);    if (message) @@ -725,7 +719,11 @@ check_no_leftovers (BusContext *context)                              &nmd);    if (nmd.failed) -    return FALSE; +    { +      _dbus_verbose ("%s: leftover message found\n", +                     _DBUS_FUNCTION_NAME); +      return FALSE; +    }    else      return TRUE;  } @@ -738,17 +736,19 @@ check_hello_message (BusContext     *context,                       DBusConnection *connection)  {    DBusMessage *message; +  DBusMessage *name_message;    dbus_uint32_t serial;    dbus_bool_t retval;    DBusError error; -  char *name; -  char *acquired; +  const char *name; +  const char *acquired;    retval = FALSE;    dbus_error_init (&error);    name = NULL;    acquired = NULL;    message = NULL; +  name_message = NULL;    _dbus_verbose ("check_hello_message for %p\n", connection); @@ -889,9 +889,10 @@ check_hello_message (BusContext     *context,        if (socd.failed)          goto out; -       + +      name_message = message;        /* Client should also have gotten ServiceAcquired */ -      dbus_message_unref (message); +        message = pop_message_waiting_for_memory (connection);        if (message == NULL)          { @@ -935,6 +936,7 @@ check_hello_message (BusContext     *context,                        acquired, name);            goto out;          } +      acquired = NULL;      }    if (!check_no_leftovers (context)) @@ -943,13 +945,15 @@ check_hello_message (BusContext     *context,    retval = TRUE;   out: -  dbus_error_free (&error); +  _dbus_verbose ("ending %s retval = %d\n", _DBUS_FUNCTION_NAME, retval); -  dbus_free (name); -  dbus_free (acquired); +  dbus_error_free (&error);    if (message)      dbus_message_unref (message); + +  if (name_message) +    dbus_message_unref (name_message);    return retval;  } @@ -1075,7 +1079,7 @@ check_get_connection_unix_user (BusContext     *context,    base_service_name = dbus_bus_get_base_service (connection);    if (!dbus_message_append_args (message,  -                                 DBUS_TYPE_STRING, base_service_name, +                                 DBUS_TYPE_STRING, &base_service_name,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -1212,7 +1216,7 @@ check_get_connection_unix_process_id (BusContext     *context,    base_service_name = dbus_bus_get_base_service (connection);    if (!dbus_message_append_args (message,  -                                 DBUS_TYPE_STRING, base_service_name, +                                 DBUS_TYPE_STRING, &base_service_name,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -1344,6 +1348,7 @@ check_add_match_all (BusContext     *context,    dbus_bool_t retval;    dbus_uint32_t serial;    DBusError error; +  const char *empty = "";    retval = FALSE;    dbus_error_init (&error); @@ -1360,7 +1365,7 @@ check_add_match_all (BusContext     *context,      return TRUE;    /* empty string match rule matches everything */ -  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", +  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &empty,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -1525,6 +1530,8 @@ check_nonexistent_service_activation (BusContext     *context,    DBusMessage *message;    dbus_uint32_t serial;    dbus_bool_t retval; +  const char *nonexistent = NONEXISTENT_SERVICE_NAME; +  dbus_uint32_t flags;    message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,                                            DBUS_PATH_ORG_FREEDESKTOP_DBUS, @@ -1534,9 +1541,10 @@ check_nonexistent_service_activation (BusContext     *context,    if (message == NULL)      return TRUE; +  flags = 0;    if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, NONEXISTENT_SERVICE_NAME, -                                 DBUS_TYPE_UINT32, 0, +                                 DBUS_TYPE_STRING, &nonexistent, +                                 DBUS_TYPE_UINT32, &flags,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -1715,12 +1723,12 @@ static dbus_bool_t  check_base_service_activated (BusContext     *context,                                DBusConnection *connection,                                DBusMessage    *initial_message, -                              char          **base_service_p) +                              const char    **base_service_p)  {    DBusMessage *message;    dbus_bool_t retval;    DBusError error; -  char *base_service, *base_service_from_bus, *old_owner; +  const char *base_service, *base_service_from_bus, *old_owner;    retval = FALSE; @@ -1752,9 +1760,6 @@ check_base_service_activated (BusContext     *context,            if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))              {                dbus_error_free (&error); -              dbus_free (base_service); -              dbus_free (old_owner); -              dbus_free (base_service_from_bus);                _dbus_wait_for_memory ();                goto reget_service_name_arg;              } @@ -1805,20 +1810,14 @@ check_base_service_activated (BusContext     *context,        goto out;      } -  retval = TRUE; -    if (base_service_p) -    { -      *base_service_p = base_service; -      base_service = NULL; -    } +    *base_service_p = base_service; + +  retval = TRUE;   out:    if (message)      dbus_message_unref (message); -  dbus_free (base_service); -  dbus_free (base_service_from_bus); -  dbus_free (old_owner);    dbus_error_free (&error);    return retval; @@ -1848,7 +1847,7 @@ check_service_activated (BusContext     *context,                                "ServiceOwnerChanged"))      {        CheckServiceOwnerChangedData socd; -      char *service_name, *base_service_from_bus, *old_owner; +      const char *service_name, *base_service_from_bus, *old_owner;      reget_service_name_arg:        service_name = NULL; @@ -1864,9 +1863,6 @@ check_service_activated (BusContext     *context,            if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))              {                dbus_error_free (&error); - 	      dbus_free (service_name); - 	      dbus_free (old_owner); - 	      dbus_free (base_service_from_bus);                _dbus_wait_for_memory ();                goto reget_service_name_arg;              } @@ -1875,9 +1871,6 @@ check_service_activated (BusContext     *context,                _dbus_warn ("Message %s doesn't have a service name: %s\n",                            "ServiceOwnerChanged (creation)",                            error.message); - 	      dbus_free (service_name); - 	      dbus_free (old_owner); - 	      dbus_free (base_service_from_bus);                goto out;              }          } @@ -1886,9 +1879,6 @@ check_service_activated (BusContext     *context,          {            _dbus_warn ("Expected to see service %s created, saw %s instead\n",                        activated_name, service_name); -          dbus_free (service_name); -          dbus_free (old_owner); -          dbus_free (base_service_from_bus);            goto out;          } @@ -1896,23 +1886,16 @@ check_service_activated (BusContext     *context,          {            _dbus_warn ("ServiceOwnerChanged reports wrong base service: %s owner, expected %s instead\n",                        base_service_from_bus, base_service_name); -          dbus_free (service_name); -          dbus_free (old_owner); -          dbus_free (base_service_from_bus);            goto out;          } -      dbus_free (base_service_from_bus);        if (old_owner[0])          {            _dbus_warn ("expected a %s, got a %s\n",                        "ServiceOwnerChanged (creation)",                        "ServiceOwnerChanged (change)"); -          dbus_free (service_name); -          dbus_free (old_owner);            goto out;          } -      dbus_free (old_owner);        socd.expected_kind = SERVICE_CREATED;        socd.skip_connection = connection; @@ -1920,13 +1903,15 @@ check_service_activated (BusContext     *context,        socd.expected_service_name = service_name;        bus_test_clients_foreach (check_service_owner_changed_foreach,                                  &socd); - -      dbus_free (service_name);        if (socd.failed)          goto out;        dbus_message_unref (message); +      service_name = NULL; +      old_owner = NULL; +      base_service_from_bus = NULL; +              message = pop_message_waiting_for_memory (connection);        if (message == NULL)          { @@ -2018,7 +2003,7 @@ check_service_auto_activated (BusContext     *context,                                DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                "ServiceOwnerChanged"))      { -      char *service_name; +      const char *service_name;        CheckServiceOwnerChangedData socd;      reget_service_name_arg: @@ -2046,7 +2031,6 @@ check_service_auto_activated (BusContext     *context,          {            _dbus_warn ("Expected to see service %s created, saw %s instead\n",                        activated_name, service_name); -          dbus_free (service_name);            goto out;          } @@ -2057,8 +2041,6 @@ check_service_auto_activated (BusContext     *context,        bus_test_clients_foreach (check_service_owner_changed_foreach,  				&socd); -      dbus_free (service_name); -              if (socd.failed)          goto out; @@ -2068,6 +2050,7 @@ check_service_auto_activated (BusContext     *context,        dbus_message_unref (message);        message = NULL; +      service_name = NULL;      }    else      { @@ -2245,7 +2228,7 @@ check_send_exit_to_service (BusContext     *context,        if (!dbus_message_is_error (message,                                    DBUS_ERROR_NO_REPLY))          { -          warn_unexpected (connection, NULL, +          warn_unexpected (connection, message,                             "NoReply error from Exit() method call");            goto out;          } @@ -2355,7 +2338,7 @@ check_got_service_info (DBusMessage *message)                                "ServiceOwnerChanged"))      {        DBusError error; -      char *service_name, *old_owner, *new_owner; +      const char *service_name, *old_owner, *new_owner;        dbus_error_init (&error);      reget_service_info_data: @@ -2373,9 +2356,6 @@ check_got_service_info (DBusMessage *message)            if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))              {                dbus_error_free (&error); -              dbus_free (service_name); -              dbus_free (old_owner); -              dbus_free (new_owner);                goto reget_service_info_data;              }            else @@ -2391,9 +2371,6 @@ check_got_service_info (DBusMessage *message)        else          message_kind = GOT_SOMETHING_ELSE; -      dbus_free (service_name); -      dbus_free (old_owner); -      dbus_free (new_owner);        dbus_error_free (&error);      }    else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) @@ -2414,11 +2391,14 @@ check_existent_service_activation (BusContext     *context,                                     DBusConnection *connection)  {    DBusMessage *message; +  DBusMessage *base_service_message; +  const char *base_service;    dbus_uint32_t serial;    dbus_bool_t retval; -  char *base_service; +  const char *existent = EXISTENT_SERVICE_NAME; +  dbus_uint32_t flags; -  base_service = NULL; +  base_service_message = NULL;    message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,                                            DBUS_PATH_ORG_FREEDESKTOP_DBUS, @@ -2428,9 +2408,10 @@ check_existent_service_activation (BusContext     *context,    if (message == NULL)      return TRUE; +  flags = 0;    if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, EXISTENT_SERVICE_NAME, -                                 DBUS_TYPE_UINT32, 0, +                                 DBUS_TYPE_STRING, &existent, +                                 DBUS_TYPE_UINT32, &flags,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -2511,7 +2492,7 @@ check_existent_service_activation (BusContext     *context,                                           message, &base_service))          goto out; -      dbus_message_unref (message); +      base_service_message = message;        message = NULL;        /* We may need to block here for the test service to exit or finish up */ @@ -2620,8 +2601,8 @@ check_existent_service_activation (BusContext     *context,    if (message)      dbus_message_unref (message); -  if (base_service) -    dbus_free (base_service); +  if (base_service_message) +    dbus_message_unref (base_service_message);    return retval;  } @@ -2636,6 +2617,8 @@ check_segfault_service_activation (BusContext     *context,    DBusMessage *message;    dbus_uint32_t serial;    dbus_bool_t retval; +  const char *segv_service; +  dbus_uint32_t flags;    message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,                                            DBUS_PATH_ORG_FREEDESKTOP_DBUS, @@ -2645,10 +2628,11 @@ check_segfault_service_activation (BusContext     *context,    if (message == NULL)      return TRUE; +  segv_service = "org.freedesktop.DBus.TestSuiteSegfaultService"; +  flags = 0;    if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, -                                 "org.freedesktop.DBus.TestSuiteSegfaultService", -                                 DBUS_TYPE_UINT32, 0, +                                 DBUS_TYPE_STRING, &segv_service, +                                 DBUS_TYPE_UINT32, &flags,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -2833,11 +2817,13 @@ check_existent_service_auto_activation (BusContext     *context,  					DBusConnection *connection)  {    DBusMessage *message; +  DBusMessage *base_service_message;    dbus_uint32_t serial;    dbus_bool_t retval; -  char *base_service; +  const char *base_service; +  const char *text; -  base_service = NULL; +  base_service_message = NULL;    message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME,                                            "/org/freedesktop/TestSuite", @@ -2849,8 +2835,9 @@ check_existent_service_auto_activation (BusContext     *context,    dbus_message_set_auto_activation (message, TRUE); +  text = TEST_ECHO_MESSAGE;    if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, TEST_ECHO_MESSAGE, +                                 DBUS_TYPE_STRING, &text,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -2902,7 +2889,7 @@ check_existent_service_auto_activation (BusContext     *context,                                           message, &base_service))  	goto out; -      dbus_message_unref (message); +      base_service_message = message;        message = NULL;        /* We may need to block here for the test service to exit or finish up */ @@ -3010,8 +2997,8 @@ check_existent_service_auto_activation (BusContext     *context,    if (message)      dbus_message_unref (message); -  if (base_service) -    dbus_free (base_service); +  if (base_service_message) +    dbus_message_unref (base_service_message);    return retval;  } diff --git a/bus/driver.c b/bus/driver.c index dc640396..99e66752 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -47,10 +47,11 @@ bus_driver_send_service_owner_changed (const char     *service_name,  {    DBusMessage *message;    dbus_bool_t retval; -  const char null_service[] = { '\000' }; +  const char *null_service;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -   + +  null_service = "";    _dbus_verbose ("sending service owner changed: %s [%s -> %s]\n",                   service_name,                    old_owner ? old_owner : null_service,  @@ -70,9 +71,9 @@ bus_driver_send_service_owner_changed (const char     *service_name,      goto oom;    if (!dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, service_name, -                                 DBUS_TYPE_STRING, old_owner ? old_owner : null_service, -                                 DBUS_TYPE_STRING, new_owner ? new_owner : null_service, +                                 DBUS_TYPE_STRING, &service_name, +                                 DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service, +                                 DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service,                                   DBUS_TYPE_INVALID))      goto oom; @@ -111,7 +112,7 @@ bus_driver_send_service_lost (DBusConnection *connection,    if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||        !dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, service_name, +                                 DBUS_TYPE_STRING, &service_name,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -154,7 +155,7 @@ bus_driver_send_service_acquired (DBusConnection *connection,    if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||        !dbus_message_append_args (message, -                                 DBUS_TYPE_STRING, service_name, +                                 DBUS_TYPE_STRING, &service_name,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -341,7 +342,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,      }    if (!dbus_message_append_args (welcome, -                                 DBUS_TYPE_STRING, name, +                                 DBUS_TYPE_STRING, &name,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (welcome); @@ -374,6 +375,9 @@ bus_driver_handle_list_services (DBusConnection *connection,    int len;    char **services;    BusRegistry *registry; +  int i; +  DBusMessageIter iter; +  DBusMessageIter sub;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -392,10 +396,12 @@ bus_driver_handle_list_services (DBusConnection *connection,        BUS_SET_OOM (error);        return FALSE;      } + +  dbus_message_append_iter_init (reply, &iter); -  if (!dbus_message_append_args (reply, -                                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, services, len, -                                 DBUS_TYPE_INVALID)) +  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, +                                         DBUS_TYPE_STRING_AS_STRING, +                                         &sub))      {        dbus_free_string_array (services);        dbus_message_unref (reply); @@ -403,6 +409,28 @@ bus_driver_handle_list_services (DBusConnection *connection,        return FALSE;      } +  i = 0; +  while (i < len) +    { +      if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, +                                           &services[i])) +        { +          dbus_free_string_array (services); +          dbus_message_unref (reply); +          BUS_SET_OOM (error); +          return FALSE; +        } +      ++i; +    } + +  if (!dbus_message_iter_close_container (&iter, &sub)) +    { +      dbus_free_string_array (services); +      dbus_message_unref (reply); +      BUS_SET_OOM (error); +      return FALSE; +    } +      dbus_free_string_array (services);    if (!bus_transaction_send_from_driver (transaction, connection, reply)) @@ -426,7 +454,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,  {    DBusMessage *reply;    DBusString service_name; -  char *name; +  const char *name;    int service_reply;    dbus_uint32_t flags;    dbus_bool_t retval; @@ -462,7 +490,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,        goto out;      } -  if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, DBUS_TYPE_INVALID)) +  if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))      {        BUS_SET_OOM (error);        goto out; @@ -477,7 +505,6 @@ bus_driver_handle_acquire_service (DBusConnection *connection,    retval = TRUE;   out: -  dbus_free (name);    if (reply)      dbus_message_unref (reply);    return retval; @@ -492,8 +519,8 @@ bus_driver_handle_service_exists (DBusConnection *connection,    DBusMessage *reply;    DBusString service_name;    BusService *service; -  dbus_bool_t service_exists; -  char *name; +  unsigned char service_exists; +  const char *name;    dbus_bool_t retval;    BusRegistry *registry; @@ -527,7 +554,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,      }    if (!dbus_message_append_args (reply, -                                 DBUS_TYPE_BOOLEAN, service_exists, +                                 DBUS_TYPE_BOOLEAN, &service_exists,                                   0))      {        BUS_SET_OOM (error); @@ -545,7 +572,6 @@ bus_driver_handle_service_exists (DBusConnection *connection,   out:    if (reply)      dbus_message_unref (reply); -  dbus_free (name);    return retval;  } @@ -557,7 +583,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,                                      DBusError      *error)  {    dbus_uint32_t flags; -  char *name; +  const char *name;    dbus_bool_t retval;    BusActivation *activation; @@ -588,7 +614,6 @@ bus_driver_handle_activate_service (DBusConnection *connection,    retval = TRUE;   out: -  dbus_free (name);    return retval;  } @@ -626,7 +651,7 @@ bus_driver_handle_add_match (DBusConnection *connection,                               DBusError      *error)  {    BusMatchRule *rule; -  char *text; +  const char *text;    DBusString str;    BusMatchmaker *matchmaker; @@ -677,7 +702,6 @@ bus_driver_handle_add_match (DBusConnection *connection,      }    bus_match_rule_unref (rule); -  dbus_free (text);    return TRUE; @@ -685,8 +709,6 @@ bus_driver_handle_add_match (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_SET (error);    if (rule)      bus_match_rule_unref (rule); -  if (text) -    dbus_free (text);    return FALSE;  } @@ -697,7 +719,7 @@ bus_driver_handle_remove_match (DBusConnection *connection,                                  DBusError      *error)  {    BusMatchRule *rule; -  char *text; +  const char *text;    DBusString str;    BusMatchmaker *matchmaker; @@ -733,7 +755,6 @@ bus_driver_handle_remove_match (DBusConnection *connection,      goto failed;    bus_match_rule_unref (rule); -  dbus_free (text);    return TRUE; @@ -741,8 +762,6 @@ bus_driver_handle_remove_match (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_SET (error);    if (rule)      bus_match_rule_unref (rule); -  if (text) -    dbus_free (text);    return FALSE;  } @@ -752,7 +771,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,  				     DBusMessage    *message,  				     DBusError      *error)  { -  char *text; +  const char *text;    const char *base_name;    DBusString str;    BusRegistry *registry; @@ -796,7 +815,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,      goto oom;    if (! dbus_message_append_args (reply,  -				  DBUS_TYPE_STRING, base_name, +				  DBUS_TYPE_STRING, &base_name,  				  DBUS_TYPE_INVALID))      goto oom; @@ -804,7 +823,6 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,      goto oom;    dbus_message_unref (reply); -  dbus_free (text);    return TRUE; @@ -815,7 +833,6 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_SET (error);    if (reply)      dbus_message_unref (reply); -  dbus_free (text);    return FALSE;  } @@ -825,13 +842,14 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,                                              DBusMessage    *message,                                              DBusError      *error)  { -  char *service; +  const char *service;    DBusString str;    BusRegistry *registry;    BusService *serv;    DBusConnection *conn;    DBusMessage *reply;    unsigned long uid; +  dbus_uint32_t uid32;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -871,8 +889,9 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,        goto failed;      } +  uid32 = uid;    if (! dbus_message_append_args (reply, -                                  DBUS_TYPE_UINT32, (dbus_uint32_t) uid, +                                  DBUS_TYPE_UINT32, &uid32,                                    DBUS_TYPE_INVALID))      goto oom; @@ -880,7 +899,6 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,      goto oom;    dbus_message_unref (reply); -  dbus_free (service);    return TRUE; @@ -891,7 +909,6 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_SET (error);    if (reply)      dbus_message_unref (reply); -  dbus_free (service);    return FALSE;  } @@ -901,13 +918,14 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,  						  DBusMessage    *message,  						  DBusError      *error)  { -  char *service; +  const char *service;    DBusString str;    BusRegistry *registry;    BusService *serv;    DBusConnection *conn;    DBusMessage *reply;    unsigned long pid; +  dbus_uint32_t pid32;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -947,8 +965,9 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,        goto failed;      } +  pid32 = pid;    if (! dbus_message_append_args (reply, -                                  DBUS_TYPE_UINT32, (dbus_uint32_t) pid, +                                  DBUS_TYPE_UINT32, &pid32,                                    DBUS_TYPE_INVALID))      goto oom; @@ -956,7 +975,6 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,      goto oom;    dbus_message_unref (reply); -  dbus_free (service);    return TRUE; @@ -967,7 +985,6 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_SET (error);    if (reply)      dbus_message_unref (reply); -  dbus_free (service);    return FALSE;  } diff --git a/bus/services.c b/bus/services.c index 1036947a..8f223f4e 100644 --- a/bus/services.c +++ b/bus/services.c @@ -156,13 +156,18 @@ bus_registry_ensure (BusRegistry               *registry,    service->registry = registry;      service->refcount = 1; -   + +  _dbus_verbose ("copying string %p '%s' to service->name\n", +                 service_name, _dbus_string_get_const_data (service_name));    if (!_dbus_string_copy_data (service_name, &service->name))      {        _dbus_mem_pool_dealloc (registry->service_pool, service);        BUS_SET_OOM (error);        return NULL;      } +  _dbus_verbose ("copied string %p '%s' to '%s'\n", +                 service_name, _dbus_string_get_const_data (service_name), +                 service->name);    if (!bus_driver_send_service_owner_changed (service->name,   					      NULL, diff --git a/bus/signals.c b/bus/signals.c index fc8e63da..2b5aa13f 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -23,6 +23,7 @@  #include "signals.h"  #include "services.h"  #include "utils.h" +#include <dbus/dbus-marshal-validate.h>  struct BusMatchRule  { @@ -656,7 +657,7 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                goto failed;              } -          if (!_dbus_string_validate_service (&tmp_str, 0, len)) +          if (!_dbus_validate_service (&tmp_str, 0, len))              {                dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,                                "Sender service name '%s' is invalid\n", value); @@ -678,7 +679,7 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                goto failed;              } -          if (!_dbus_string_validate_interface (&tmp_str, 0, len)) +          if (!_dbus_validate_interface (&tmp_str, 0, len))              {                dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,                                "Interface name '%s' is invalid\n", value); @@ -700,7 +701,7 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                goto failed;              } -          if (!_dbus_string_validate_member (&tmp_str, 0, len)) +          if (!_dbus_validate_member (&tmp_str, 0, len))              {                dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,                                "Member name '%s' is invalid\n", value); @@ -722,7 +723,7 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                goto failed;              } -          if (!_dbus_string_validate_path (&tmp_str, 0, len)) +          if (!_dbus_validate_path (&tmp_str, 0, len))              {                dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,                                "Path '%s' is invalid\n", value); @@ -744,7 +745,7 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                goto failed;              } -          if (!_dbus_string_validate_service (&tmp_str, 0, len)) +          if (!_dbus_validate_service (&tmp_str, 0, len))              {                dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,                                "Destination service name '%s' is invalid\n", value); diff --git a/dbus/.cvsignore b/dbus/.cvsignore index 02bb3e6e..51cd09cb 100644 --- a/dbus/.cvsignore +++ b/dbus/.cvsignore @@ -12,3 +12,5 @@ dbus-test  dbus-arch-deps.h  .dbus-keyrings  dbus-glib-error-enum.h +*.gcno +*.gcda diff --git a/dbus/Makefile.am b/dbus/Makefile.am index a9ec8808..12c9444f 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -54,6 +54,12 @@ DBUS_LIB_SOURCES=				\  	dbus-errors.c				\  	dbus-keyring.c				\  	dbus-keyring.h				\ +	dbus-marshal-header.c			\ +	dbus-marshal-header.h			\ +	dbus-marshal-recursive.c		\ +	dbus-marshal-recursive.h		\ +	dbus-marshal-validate.c			\ +	dbus-marshal-validate.h			\  	dbus-message.c				\  	dbus-message-internal.h			\  	dbus-object-tree.c			\ @@ -98,13 +104,11 @@ DBUS_SHARED_SOURCES=				\  	dbus-internals.h			\  	dbus-list.c				\  	dbus-list.h				\ -	dbus-marshal.c				\ -	dbus-marshal.h				\ +	dbus-marshal-basic.c			\ +	dbus-marshal-basic.h			\  	dbus-memory.c				\  	dbus-mempool.c				\  	dbus-mempool.h				\ -	dbus-message-builder.c			\ -	dbus-message-builder.h			\  	dbus-spawn.c				\  	dbus-spawn.h				\  	dbus-string.c				\ diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index 2ed2af37..f32f1c1d 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -29,7 +29,6 @@  #include "dbus-string.h"  #include "dbus-hash.h"  #include "dbus-internals.h" -#include "dbus-marshal.h"  #include "dbus-userdb.h"  /** diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index be296fc7..bc1750b6 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -479,8 +479,13 @@ dbus_bus_register (DBusConnection *connection,                                     DBUS_TYPE_INVALID))      goto out; -  bd->base_service = name; - +  bd->base_service = _dbus_strdup (name); +  if (bd->base_service == NULL) +    { +      _DBUS_SET_OOM (error); +      goto out; +    } +      retval = TRUE;   out: @@ -578,7 +583,7 @@ dbus_bus_get_unix_user (DBusConnection *connection,      }    if (!dbus_message_append_args (message, -				 DBUS_TYPE_STRING, service, +				 DBUS_TYPE_STRING, &service,  				 DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -659,8 +664,8 @@ dbus_bus_acquire_service (DBusConnection *connection,      }    if (!dbus_message_append_args (message, -				 DBUS_TYPE_STRING, service_name, -				 DBUS_TYPE_UINT32, flags, +				 DBUS_TYPE_STRING, &service_name, +				 DBUS_TYPE_UINT32, &flags,  				 DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -731,7 +736,7 @@ dbus_bus_service_exists (DBusConnection *connection,      }    if (!dbus_message_append_args (message, -				 DBUS_TYPE_STRING, service_name, +				 DBUS_TYPE_STRING, &service_name,  				 DBUS_TYPE_INVALID))      {        dbus_message_unref (message); @@ -791,8 +796,8 @@ dbus_bus_activate_service (DBusConnection *connection,                                        DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                        "ActivateService"); -  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name, -			  	 DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID)) +  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &service_name, +			  	 DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))      {        dbus_message_unref (msg);        _DBUS_SET_OOM (error); @@ -895,7 +900,7 @@ dbus_bus_add_match (DBusConnection *connection,        return;      } -  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule, +  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (msg); @@ -933,7 +938,7 @@ dbus_bus_remove_match (DBusConnection *connection,                                        DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                        "RemoveMatch"); -  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule, +  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule,                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (msg); diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 41ca0a77..197d186c 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -38,7 +38,6 @@  #include "dbus-string.h"  #include "dbus-pending-call.h"  #include "dbus-object-tree.h" -#include "dbus-marshal.h"  #if 0  #define CONNECTION_LOCK(connection)   do {                      \ @@ -1562,15 +1561,6 @@ _dbus_connection_send_preallocated_unlocked (DBusConnection       *connection,    connection->n_outgoing += 1;    sig = dbus_message_get_signature (message); -#ifndef DBUS_DISABLE_ASSERT -  { -    DBusString foo; -    _dbus_verbose (" validating signature '%s'\n", sig); -    _dbus_string_init_const (&foo, sig); -    _dbus_assert (_dbus_string_validate_signature (&foo, 0, -                                                   _dbus_string_get_length (&foo))); -  } -#endif    _dbus_verbose ("Message %p (%d %s %s '%s') added to outgoing queue %p, %d pending to send\n",                   message, diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 6d2395fd..2aa26805 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -355,42 +355,6 @@ _dbus_string_array_contains (const char **array,  }  /** - * Returns a string describing the given type. - * - * @param type the type to describe - * @returns a constant string describing the type - */ -const char * -_dbus_type_to_string (int type) -{ -  switch (type) -    { -    case DBUS_TYPE_INVALID: -      return "invalid"; -    case DBUS_TYPE_NIL: -      return "nil"; -    case DBUS_TYPE_BOOLEAN: -      return "boolean"; -    case DBUS_TYPE_INT32: -      return "int32"; -    case DBUS_TYPE_UINT32: -      return "uint32"; -    case DBUS_TYPE_DOUBLE: -      return "double"; -    case DBUS_TYPE_STRING: -      return "string"; -    case DBUS_TYPE_CUSTOM: -      return "custom"; -    case DBUS_TYPE_ARRAY: -      return "array"; -    case DBUS_TYPE_DICT: -      return "dict"; -    default: -      return "unknown"; -    } -} - -/**   * Returns a string describing the given name.   *   * @param header_field the field to describe @@ -525,6 +489,9 @@ _dbus_test_oom_handling (const char             *description,                           void                   *data)  {    int approx_mallocs; +  const char *setting; +  int max_failures_to_try; +  int i;    /* Run once to see about how many mallocs are involved */ @@ -540,21 +507,30 @@ _dbus_test_oom_handling (const char             *description,    _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",                   description, approx_mallocs); -  _dbus_set_fail_alloc_failures (1); -  if (!run_failing_each_malloc (approx_mallocs, description, func, data)) -    return FALSE; - -  _dbus_set_fail_alloc_failures (2); -  if (!run_failing_each_malloc (approx_mallocs, description, func, data)) -    return FALSE; -   -  _dbus_set_fail_alloc_failures (3); -  if (!run_failing_each_malloc (approx_mallocs, description, func, data)) -    return FALSE; +  setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES"); +  if (setting != NULL) +    { +      DBusString str; +      long v; +      _dbus_string_init_const (&str, setting); +      v = 4; +      if (!_dbus_string_parse_int (&str, 0, &v, NULL)) +        _dbus_warn ("couldn't parse '%s' as integer\n", setting); +      max_failures_to_try = v; +    } +  else +    { +      max_failures_to_try = 4; +    } -  _dbus_set_fail_alloc_failures (4); -  if (!run_failing_each_malloc (approx_mallocs, description, func, data)) -    return FALSE; +  i = setting ? max_failures_to_try - 1 : 1; +  while (i < max_failures_to_try) +    { +      _dbus_set_fail_alloc_failures (i); +      if (!run_failing_each_malloc (approx_mallocs, description, func, data)) +        return FALSE; +      ++i; +    }    _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",                   description); diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 8560d4ec..d1c65615 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -170,6 +170,7 @@ extern const char _dbus_return_if_fail_warning_format[];  #define _DBUS_ALIGN_ADDRESS(this, boundary) \    ((void*)_DBUS_ALIGN_VALUE(this, boundary)) +  char*       _dbus_strdup                (const char  *str);  void*       _dbus_memdup                (const void  *mem,                                           size_t       n_bytes); @@ -207,13 +208,12 @@ dbus_bool_t _dbus_set_fd_nonblocking (int             fd,                                        DBusError      *error);  void _dbus_verbose_bytes           (const unsigned char *data, -                                    int                  len); +                                    int                  len, +                                    int                  offset);  void _dbus_verbose_bytes_of_string (const DBusString    *str,                                      int                  start,                                      int                  len); - -const char* _dbus_type_to_string         (int type);  const char* _dbus_header_field_to_string (int header_field);  extern const char _dbus_no_memory_message[]; diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c index 99369d48..b3089bbc 100644 --- a/dbus/dbus-mainloop.c +++ b/dbus/dbus-mainloop.c @@ -30,7 +30,7 @@  #define MAINLOOP_SPEW 0 -#ifdef MAINLOOP_SPEW +#if MAINLOOP_SPEW  #ifdef DBUS_ENABLE_VERBOSE_MODE  static const char*  watch_flags_to_string (int flags) diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index 11ebfaf1..7504019b 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -150,6 +150,7 @@ swap_8_octets (DBusBasicValue    *value,      }  } +#if 0  static DBusBasicValue  unpack_8_octets (int                  byte_order,                   const unsigned char *data) @@ -171,6 +172,7 @@ unpack_8_octets (int                  byte_order,    return r;  } +#endif  /**   * Unpacks a 32 bit unsigned integer from a data pointer @@ -404,10 +406,12 @@ _dbus_marshal_set_basic (DBusString       *str,        break;      case DBUS_TYPE_STRING:      case DBUS_TYPE_OBJECT_PATH: +      _dbus_assert (vp->str != NULL);        return set_string (str, pos, vp->str, byte_order,                           old_end_pos, new_end_pos);        break;      case DBUS_TYPE_SIGNATURE: +      _dbus_assert (vp->str != NULL);        return set_signature (str, pos, vp->str, byte_order,                              old_end_pos, new_end_pos);        break; @@ -429,6 +433,8 @@ read_4_octets (const DBusString *str,    if (new_pos)      *new_pos = pos + 4; +  _dbus_assert (pos + 4 <= _dbus_string_get_length (str)); +      return unpack_4_octets (byte_order,                            _dbus_string_get_const_data (str) + pos);  } @@ -554,52 +560,52 @@ _dbus_marshal_read_basic (const DBusString      *str,  }  /** - * Reads an array of fixed-length basic values.  Does not work for - * arrays of string or container types. + * Reads a block of fixed-length basic values, as an optimization + * vs. reading each one individually into a new buffer.   * - * This function returns the array in-place; it does not make a copy, + * This function returns the data in-place; it does not make a copy,   * and it does not swap the bytes.   *   * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back   * and the "value" argument should be a "const double**" and so on.   * - * @todo last I checked only the test suite uses this function - * + * @todo we aren't using this function (except in the test suite) + *    * @param str the string to read from   * @param pos position to read from   * @param element_type type of array elements   * @param value place to return the array - * @param n_elements place to return number of array elements + * @param n_elements number of array elements to read   * @param byte_order the byte order, used to read the array length   * @param new_pos #NULL or location to store a position after the elements   */  void -_dbus_marshal_read_fixed_array  (const DBusString *str, +_dbus_marshal_read_fixed_multi  (const DBusString *str,                                   int               pos,                                   int               element_type,                                   void             *value, -                                 int              *n_elements, +                                 int               n_elements,                                   int               byte_order,                                   int              *new_pos)  { -  dbus_uint32_t array_len; +  int array_len;    int alignment;    _dbus_assert (_dbus_type_is_fixed (element_type));    _dbus_assert (_dbus_type_is_basic (element_type)); -  pos = _DBUS_ALIGN_VALUE (pos, 4); - -  array_len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos); - +#if 0 +  _dbus_verbose ("reading %d elements of %s\n", +                 n_elements, _dbus_type_to_string (element_type)); +#endif +      alignment = _dbus_type_get_alignment (element_type);    pos = _DBUS_ALIGN_VALUE (pos, alignment); +   +  array_len = n_elements * alignment;    *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len); - -  *n_elements = array_len / alignment; -    if (new_pos)      *new_pos = pos + array_len;  } @@ -682,16 +688,12 @@ marshal_len_followed_by_bytes (int                  marshal_as,    if (insert_at > _dbus_string_get_length (str))      _dbus_warn ("insert_at = %d string len = %d data_len = %d\n",                  insert_at, _dbus_string_get_length (str), data_len); - +      if (marshal_as == MARSHAL_AS_BYTE_ARRAY)      value_len = data_len;    else      value_len = data_len + 1; /* value has a nul */ -  /* FIXME this is probably broken for byte arrays because -   * DBusString wants strings to be nul-terminated? -   * Maybe I planned on this when writing init_const_len though -   */    _dbus_string_init_const_len (&value_str, value, value_len);    pos = insert_at; @@ -814,9 +816,11 @@ _dbus_marshal_write_basic (DBusString *str,      case DBUS_TYPE_STRING:      case DBUS_TYPE_OBJECT_PATH: +      _dbus_assert (vp->str != NULL);        return marshal_string (str, insert_at, vp->str, byte_order, pos_after);        break;      case DBUS_TYPE_SIGNATURE: +      _dbus_assert (vp->str != NULL);        return marshal_signature (str, insert_at, vp->str, pos_after);        break;      default: @@ -834,9 +838,23 @@ marshal_1_octets_array (DBusString          *str,                          int                  byte_order,                          int                 *pos_after)  { -  return marshal_len_followed_by_bytes (MARSHAL_AS_BYTE_ARRAY, -                                        str, insert_at, value, n_elements, -                                        byte_order, pos_after); +  int pos; +  DBusString value_str; + +  _dbus_string_init_const_len (&value_str, value, n_elements); + +  pos = insert_at; + +  if (!_dbus_string_copy_len (&value_str, 0, n_elements, +                              str, pos)) +    return FALSE; + +  pos += n_elements; + +  if (pos_after) +    *pos_after = pos; + +  return TRUE;  }  static void @@ -885,7 +903,7 @@ swap_array (DBusString *str,  }  static dbus_bool_t -marshal_fixed_array (DBusString           *str, +marshal_fixed_multi (DBusString           *str,                       int                   insert_at,                       const DBusBasicValue *value,                       int                   n_elements, @@ -896,18 +914,15 @@ marshal_fixed_array (DBusString           *str,    int old_string_len;    int array_start;    DBusString t; +  int len_in_bytes; +  _dbus_assert (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / alignment); +      old_string_len = _dbus_string_get_length (str); -  /*  The array length is the length in bytes of the array, -   * *excluding* alignment padding. -   */ -  if (!marshal_4_octets (str, insert_at, n_elements * alignment, -                         byte_order, &array_start)) -    goto error; - -  _dbus_verbose ("marshaled len %d at %d array start %d\n", n_elements * alignment, insert_at, array_start); - +  len_in_bytes = n_elements * alignment; +  array_start = insert_at; +      /* Note that we do alignment padding unconditionally     * even if the array is empty; this means that     * padding + len is always equal to the number of bytes @@ -919,7 +934,7 @@ marshal_fixed_array (DBusString           *str,    _dbus_string_init_const_len (&t,                                 (const unsigned char*) value, -                               n_elements * alignment); +                               len_in_bytes);    if (!_dbus_string_copy (&t, 0,                            str, array_start)) @@ -927,6 +942,9 @@ marshal_fixed_array (DBusString           *str,    swap_array (str, array_start, n_elements, byte_order, alignment); +  if (pos_after) +    *pos_after = array_start + len_in_bytes; +      return TRUE;   error: @@ -937,9 +955,9 @@ marshal_fixed_array (DBusString           *str,  }  /** - * Marshals an array of values of fixed-length type. - * _dbus_type_is_fixed() returns #TRUE for these types, - * which are the basic types minus the string-like types. + * Marshals a block of values of fixed-length type all at once, as an + * optimization.  _dbus_type_is_fixed() returns #TRUE for fixed-length + * types, which are the basic types minus the string-like types.   *   * The value argument should be the adddress of an   * array, so e.g. "const dbus_uint32_t**" @@ -948,13 +966,13 @@ marshal_fixed_array (DBusString           *str,   * @param insert_at where to insert the value   * @param element_type type of array elements   * @param value address of an array to marshal - * @param len number of elements in the array + * @param n_elements number of elements in the array   * @param byte_order byte order   * @param pos_after #NULL or the position after the type   * @returns #TRUE on success   **/  dbus_bool_t -_dbus_marshal_write_fixed_array (DBusString *str, +_dbus_marshal_write_fixed_multi (DBusString *str,                                   int         insert_at,                                   int         element_type,                                   const void *value, @@ -963,9 +981,15 @@ _dbus_marshal_write_fixed_array (DBusString *str,                                   int        *pos_after)  {    const void* vp = *(const DBusBasicValue**)value; - +      _dbus_assert (_dbus_type_is_fixed (element_type)); +  _dbus_assert (n_elements >= 0); +#if 0 +  _dbus_verbose ("writing %d elements of %s\n", +                 n_elements, _dbus_type_to_string (element_type)); +#endif +      switch (element_type)      {      case DBUS_TYPE_BOOLEAN: @@ -976,12 +1000,12 @@ _dbus_marshal_write_fixed_array (DBusString *str,        break;      case DBUS_TYPE_INT32:      case DBUS_TYPE_UINT32: -      return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 4, pos_after); +      return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after);        break;      case DBUS_TYPE_INT64:      case DBUS_TYPE_UINT64:      case DBUS_TYPE_DOUBLE: -      return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 8, pos_after); +      return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 8, pos_after);        break;      default: @@ -1008,6 +1032,9 @@ _dbus_marshal_skip_basic (const DBusString      *str,                            int                    byte_order,                            int                   *pos)  { +  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || +                byte_order == DBUS_BIG_ENDIAN); +      switch (type)      {      case DBUS_TYPE_BYTE: @@ -1031,7 +1058,7 @@ _dbus_marshal_skip_basic (const DBusString      *str,          int len;          len = _dbus_marshal_read_uint32 (str, *pos, byte_order, pos); - +                  *pos += len + 1; /* length plus nul */        }        break; @@ -1232,6 +1259,50 @@ _dbus_type_is_fixed (int typecode)  }  /** + * Returns a string describing the given type. + * + * @param typecode the type to describe + * @returns a constant string describing the type + */ +const char * +_dbus_type_to_string (int typecode) +{ +  switch (typecode) +    { +    case DBUS_TYPE_INVALID: +      return "invalid"; +    case DBUS_TYPE_BOOLEAN: +      return "boolean"; +    case DBUS_TYPE_BYTE: +      return "byte"; +    case DBUS_TYPE_INT32: +      return "int32"; +    case DBUS_TYPE_UINT32: +      return "uint32"; +    case DBUS_TYPE_DOUBLE: +      return "double"; +    case DBUS_TYPE_STRING: +      return "string"; +    case DBUS_TYPE_OBJECT_PATH: +      return "object_path"; +    case DBUS_TYPE_SIGNATURE: +      return "signature"; +    case DBUS_TYPE_STRUCT: +      return "struct"; +    case DBUS_TYPE_ARRAY: +      return "array"; +    case DBUS_TYPE_VARIANT: +      return "variant"; +    case DBUS_STRUCT_BEGIN_CHAR: +      return "begin_struct"; +    case DBUS_STRUCT_END_CHAR: +      return "end_struct"; +    default: +      return "unknown"; +    } +} + +/**   * If in verbose mode, print a block of binary data.   *   * @todo right now it prints even if not in verbose mode @@ -1367,6 +1438,10 @@ swap_test_array (void *array,                   int   alignment)  {    DBusString t; + +  if (alignment == 1) +    return; +      _dbus_string_init_const_len (&t, array, len_bytes);    swap_array (&t, 0, len_bytes / alignment, byte_order, alignment);  } @@ -1420,8 +1495,13 @@ swap_test_array (void *array,  #define MARSHAL_FIXED_ARRAY(typename, byte_order, literal)                                      \    do {                                                                                          \ +     int next;                                                                                  \ +     v_UINT32 = sizeof(literal);                                                                \ +     if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_UINT32, &v_UINT32,                    \ +                                     byte_order, &next))                                        \ +       _dbus_assert_not_reached ("no memory");                                                  \       v_ARRAY_##typename = literal;                                                              \ -     if (!_dbus_marshal_write_fixed_array (&str, pos, DBUS_TYPE_##typename,                     \ +     if (!_dbus_marshal_write_fixed_multi (&str, next, DBUS_TYPE_##typename,                    \                                             &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal),      \                                             byte_order, NULL))                                   \         _dbus_assert_not_reached ("no memory");                                                  \ @@ -1429,10 +1509,14 @@ swap_test_array (void *array,  #define DEMARSHAL_FIXED_ARRAY(typename, byte_order)                                             \    do {                                                                                          \ -    _dbus_marshal_read_fixed_array (&str, pos, DBUS_TYPE_##typename, &v_ARRAY_##typename,       \ -                                    &n_elements, byte_order, &pos);                             \ -    swap_test_array (v_ARRAY_##typename, n_elements * sizeof(v_ARRAY_##typename[0]),            \ -                     byte_order, sizeof(v_ARRAY_##typename[0]));                                \ +    int next;                                                                                   \ +    alignment = _dbus_type_get_alignment (DBUS_TYPE_##typename);                                \ +    v_UINT32 = _dbus_marshal_read_uint32 (&str, dump_pos, byte_order, &next);                   \ +    _dbus_marshal_read_fixed_multi (&str, next, DBUS_TYPE_##typename, &v_ARRAY_##typename,      \ +                                    v_UINT32/alignment,                                         \ +                                    byte_order, NULL);                                          \ +    swap_test_array (v_ARRAY_##typename, v_UINT32,                                              \ +                     byte_order, alignment);                                                    \    } while (0)  #define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal)                  \ @@ -1461,9 +1545,10 @@ swap_test_array (void *array,  dbus_bool_t  _dbus_marshal_test (void)  { +  int alignment;    DBusString str;    int pos, dump_pos; -  int n_elements; +  unsigned char array1[5] = { 3, 4, 0, 1, 9 };    dbus_int32_t array4[3] = { 123, 456, 789 };  #ifdef DBUS_HAVE_INT64    dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff), @@ -1471,6 +1556,7 @@ _dbus_marshal_test (void)                               DBUS_INT64_CONSTANT (0x789ffffffff) };    dbus_int64_t *v_ARRAY_INT64;  #endif +  unsigned char *v_ARRAY_BYTE;    dbus_int32_t *v_ARRAY_INT32;    double *v_ARRAY_DOUBLE;    DBusString t; @@ -1553,6 +1639,9 @@ _dbus_marshal_test (void)    MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4);    MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4); +  MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_BIG_ENDIAN, array1); +  MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_LITTLE_ENDIAN, array1); +    #ifdef DBUS_HAVE_INT64    MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8);    MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8); @@ -1675,16 +1764,18 @@ _dbus_marshal_test (void)                                      _dbus_string_get_const_data (&str)));    /* unsigned little */ -  _dbus_marshal_set_uint32 (&str, DBUS_LITTLE_ENDIAN, -                            0, 0x123456); +  _dbus_marshal_set_uint32 (&str, +                            0, 0x123456, +                            DBUS_LITTLE_ENDIAN);    _dbus_assert (0x123456 ==                  _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN,                                       _dbus_string_get_const_data (&str)));    /* unsigned big */ -  _dbus_marshal_set_uint32 (&str, DBUS_BIG_ENDIAN, -                            0, 0x123456); +  _dbus_marshal_set_uint32 (&str, +                            0, 0x123456, +                            DBUS_BIG_ENDIAN);    _dbus_assert (0x123456 ==                  _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h index 72ae2834..ddfce18e 100644 --- a/dbus/dbus-marshal-basic.h +++ b/dbus/dbus-marshal-basic.h @@ -35,120 +35,6 @@  #error "config.h not included here"  #endif -/****************************************************** Remove later */ -#undef DBUS_TYPE_INVALID -#undef DBUS_TYPE_NIL -#undef DBUS_TYPE_CUSTOM -#undef DBUS_TYPE_BYTE -#undef DBUS_TYPE_INT32 -#undef DBUS_TYPE_UINT32 -#undef DBUS_TYPE_INT64 -#undef DBUS_TYPE_UINT64 -#undef DBUS_TYPE_DOUBLE -#undef DBUS_TYPE_STRING -#undef DBUS_TYPE_OBJECT_PATH -#undef DBUS_TYPE_ARRAY -#undef DBUS_TYPE_DICT -#undef DBUS_TYPE_VARIANT -#undef DBUS_TYPE_STRUCT -#undef DBUS_NUMBER_OF_TYPES - - -/* Never a legitimate type */ -#define DBUS_TYPE_INVALID       ((int) '\0') -#define DBUS_TYPE_INVALID_AS_STRING        "\0" - -/* Primitive types */ -#define DBUS_TYPE_BYTE          ((int) 'y') -#define DBUS_TYPE_BYTE_AS_STRING           "y" -#define DBUS_TYPE_BOOLEAN       ((int) 'b') -#define DBUS_TYPE_BOOLEAN_AS_STRING        "b" -#define DBUS_TYPE_INT32         ((int) 'i') -#define DBUS_TYPE_INT32_AS_STRING          "i" - -#define DBUS_TYPE_UINT32        ((int) 'u') -#define DBUS_TYPE_UINT32_AS_STRING         "u" -#define DBUS_TYPE_INT64         ((int) 'x') -#define DBUS_TYPE_INT64_AS_STRING          "x" -#define DBUS_TYPE_UINT64        ((int) 't') -#define DBUS_TYPE_UINT64_AS_STRING         "t" - -#define DBUS_TYPE_DOUBLE        ((int) 'd') -#define DBUS_TYPE_DOUBLE_AS_STRING         "d" -#define DBUS_TYPE_STRING        ((int) 's') -#define DBUS_TYPE_STRING_AS_STRING         "s" -#define DBUS_TYPE_OBJECT_PATH   ((int) 'o') -#define DBUS_TYPE_OBJECT_PATH_AS_STRING    "o" -#define DBUS_TYPE_SIGNATURE     ((int) 'g') -#define DBUS_TYPE_SIGNATURE_AS_STRING      "g" - -/* Compound types */ -#define DBUS_TYPE_ARRAY         ((int) 'a') -#define DBUS_TYPE_ARRAY_AS_STRING          "a" -#define DBUS_TYPE_VARIANT       ((int) 'v') -#define DBUS_TYPE_VARIANT_AS_STRING        "v" - -/* STRUCT is sort of special since its code can't appear in a type string, - * instead DBUS_STRUCT_BEGIN_CHAR has to appear - */ -#define DBUS_TYPE_STRUCT        ((int) 'r') -#define DBUS_TYPE_STRUCT_AS_STRING         "r" - -/* Does not count INVALID */ -#define DBUS_NUMBER_OF_TYPES    (13) - -/* characters other than typecodes that appear in type signatures */ -#define DBUS_STRUCT_BEGIN_CHAR   ((int) '(') -#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING   "(" -#define DBUS_STRUCT_END_CHAR     ((int) ')') -#define DBUS_STRUCT_END_CHAR_AS_STRING     ")" - -#define DBUS_MAXIMUM_SIGNATURE_LENGTH 255 -#define DBUS_MAXIMUM_ARRAY_LENGTH (67108864) -#define DBUS_MAXIMUM_ARRAY_LENGTH_BITS 26 -#define DBUS_MAXIMUM_MESSAGE_LENGTH (DBUS_MAXIMUM_ARRAY_LENGTH * 2) -#define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27 - -static const char * -_hack_dbus_type_to_string (int type) -{ -  switch (type) -    { -    case DBUS_TYPE_INVALID: -      return "invalid"; -    case DBUS_TYPE_BOOLEAN: -      return "boolean"; -    case DBUS_TYPE_INT32: -      return "int32"; -    case DBUS_TYPE_UINT32: -      return "uint32"; -    case DBUS_TYPE_DOUBLE: -      return "double"; -    case DBUS_TYPE_STRING: -      return "string"; -    case DBUS_TYPE_OBJECT_PATH: -      return "object_path"; -    case DBUS_TYPE_SIGNATURE: -      return "signature"; -    case DBUS_TYPE_STRUCT: -      return "struct"; -    case DBUS_TYPE_ARRAY: -      return "array"; -    case DBUS_TYPE_VARIANT: -      return "variant"; -    case DBUS_STRUCT_BEGIN_CHAR: -      return "begin_struct"; -    case DBUS_STRUCT_END_CHAR: -      return "end_struct"; -    default: -      return "unknown"; -    } -} - -#define _dbus_type_to_string(t) _hack_dbus_type_to_string(t) - -/****************************************************** Remove later */ -  #ifdef WORDS_BIGENDIAN  #define DBUS_COMPILER_BYTE_ORDER DBUS_BIG_ENDIAN  #else @@ -275,7 +161,7 @@ dbus_bool_t   _dbus_marshal_write_basic       (DBusString       *str,                                                 const void       *value,                                                 int               byte_order,                                                 int              *pos_after); -dbus_bool_t   _dbus_marshal_write_fixed_array (DBusString       *str, +dbus_bool_t   _dbus_marshal_write_fixed_multi (DBusString       *str,                                                 int               insert_at,                                                 int               element_type,                                                 const void       *value, @@ -288,11 +174,11 @@ void          _dbus_marshal_read_basic        (const DBusString *str,                                                 void             *value,                                                 int               byte_order,                                                 int              *new_pos); -void          _dbus_marshal_read_fixed_array  (const DBusString *str, +void          _dbus_marshal_read_fixed_multi  (const DBusString *str,                                                 int               pos,                                                 int               element_type,                                                 void             *value, -                                               int              *n_elements, +                                               int               n_elements,                                                 int               byte_order,                                                 int              *new_pos);  void          _dbus_marshal_skip_basic        (const DBusString *str, @@ -316,7 +202,7 @@ int           _dbus_type_get_alignment        (int               typecode);  dbus_bool_t   _dbus_type_is_basic             (int               typecode);  dbus_bool_t   _dbus_type_is_container         (int               typecode);  dbus_bool_t   _dbus_type_is_fixed             (int               typecode); - +const char*   _dbus_type_to_string            (int               typecode); diff --git a/dbus/dbus-marshal-header.c b/dbus/dbus-marshal-header.c new file mode 100644 index 00000000..34940429 --- /dev/null +++ b/dbus/dbus-marshal-header.c @@ -0,0 +1,1435 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-marshal-header.c  Managing marshaling/demarshaling of message headers + * + * 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 + * + */ + +#include "dbus-marshal-header.h" +#include "dbus-marshal-recursive.h" + +/** + * @addtogroup DBusMarshal + * + * @{ + */ + + +/* Not thread locked, but strictly const/read-only so should be OK + */ +_DBUS_STRING_DEFINE_STATIC(_dbus_header_signature_str, DBUS_HEADER_SIGNATURE); +_DBUS_STRING_DEFINE_STATIC(_dbus_local_interface_str,  DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL); +_DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str,       DBUS_PATH_ORG_FREEDESKTOP_LOCAL); + +#define FIELDS_ARRAY_SIGNATURE_OFFSET 6 +#define FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET 7 + + +/** Offset to byte order from start of header */ +#define BYTE_ORDER_OFFSET    0 +/** Offset to type from start of header */ +#define TYPE_OFFSET          1 +/** Offset to flags from start of header */ +#define FLAGS_OFFSET         2 +/** Offset to version from start of header */ +#define VERSION_OFFSET       3 +/** Offset to body length from start of header */ +#define BODY_LENGTH_OFFSET 4 +/** Offset to client serial from start of header */ +#define SERIAL_OFFSET 8 +/** Offset to fields array length from start of header */ +#define FIELDS_ARRAY_LENGTH_OFFSET 12 +/** Offset to first field in header */ +#define FIRST_FIELD_OFFSET 16 + +typedef struct +{ +  unsigned char code; +  unsigned char type; +} HeaderFieldType; + +static const HeaderFieldType +_dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = { +  { DBUS_HEADER_FIELD_INVALID, DBUS_TYPE_INVALID }, +  { DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH }, +  { DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING }, +  { DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING }, +  { DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING }, +  { DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32 }, +  { DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING }, +  { DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING }, +  { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE } +}; + +#define EXPECTED_TYPE_OF_FIELD(field) (_dbus_header_field_types[field].type) + +#define MAX_POSSIBLE_HEADER_PADDING 7 +static dbus_bool_t +reserve_header_padding (DBusHeader *header) +{ +  _dbus_assert (header->padding <= MAX_POSSIBLE_HEADER_PADDING); + +  if (!_dbus_string_lengthen (&header->data, +                              MAX_POSSIBLE_HEADER_PADDING - header->padding)) +    return FALSE; +  header->padding = MAX_POSSIBLE_HEADER_PADDING; +  return TRUE; +} + +static void +correct_header_padding (DBusHeader *header) +{ +  int unpadded_len; + +  _dbus_assert (header->padding == 7); + +  _dbus_string_shorten (&header->data, header->padding); +  unpadded_len = _dbus_string_get_length (&header->data); + +  if (!_dbus_string_align_length (&header->data, 8)) +    _dbus_assert_not_reached ("couldn't pad header though enough padding was preallocated"); + +  header->padding = _dbus_string_get_length (&header->data) - unpadded_len; +} + +#define HEADER_END_BEFORE_PADDING(header) \ +  (_dbus_string_get_length (&(header)->data) - (header)->padding) + +/** + * Invalidates all fields in the cache. This may be used when the + * cache is totally uninitialized (contains junk) so should not + * look at what's in there now. + * + * @param header the header + */ +static void +_dbus_header_cache_invalidate_all (DBusHeader *header) +{ +  int i; + +  i = 0; +  while (i <= DBUS_HEADER_FIELD_LAST) +    { +      header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_UNKNOWN; +      ++i; +    } +} + +/** + * Caches one field + * + * @param header the header + * @param field_code the field + * @param variant_reader the reader for the variant in the field + */ +static void +_dbus_header_cache_one (DBusHeader     *header, +                        int             field_code, +                        DBusTypeReader *variant_reader) +{ +  int variant_type; + +  variant_type = _dbus_type_reader_get_current_type (variant_reader); + +  header->fields[field_code].value_pos = +    _dbus_type_reader_get_value_pos (variant_reader); + +#if 0 +  _dbus_verbose ("cached value_pos %d for field %d\n", +                 header->fields[field_code].value_pos, field_code) +#endif +} + +/** + * Revalidates the fields cache + * + * @param header the header + */ +static void +_dbus_header_cache_revalidate (DBusHeader *header) +{ +  DBusTypeReader array; +  DBusTypeReader reader; +  int i; + +  i = 0; +  while (i <= DBUS_HEADER_FIELD_LAST) +    { +      header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; +      ++i; +    } + +  _dbus_type_reader_init (&reader, +                          header->byte_order, +                          &_dbus_header_signature_str, +                          FIELDS_ARRAY_SIGNATURE_OFFSET, +                          &header->data, +                          FIELDS_ARRAY_LENGTH_OFFSET); + +  _dbus_type_reader_recurse (&reader, &array); + +  while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) +    { +      DBusTypeReader sub; +      DBusTypeReader variant; +      unsigned char field_code; + +      _dbus_type_reader_recurse (&array, &sub); + +      _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); +      _dbus_type_reader_read_basic (&sub, &field_code); + +      /* Unknown fields should be ignored */ +      if (field_code > DBUS_HEADER_FIELD_LAST) +        goto next_field; + +      _dbus_type_reader_next (&sub); + +      _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_VARIANT); +      _dbus_type_reader_recurse (&sub, &variant); + +      _dbus_header_cache_one (header, field_code, &variant); + +    next_field: +      _dbus_type_reader_next (&array); +    } +} + +/** + * Checks for a field, updating the cache if required. + * + * @param header the header + * @param field the field to check + * @returns #FALSE if the field doesn't exist + */ +static dbus_bool_t +_dbus_header_cache_check (DBusHeader    *header, +                          int            field) +{ +  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + +  if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) +    _dbus_header_cache_revalidate (header); + +  if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT) +    return FALSE; + +  return TRUE; +} + +/** + * Checks whether a field is known not to exist. It may exist + * even if it's not known to exist. + * + * @param header the header + * @param field the field to check + * @returns #FALSE if the field definitely doesn't exist + */ +static dbus_bool_t +_dbus_header_cache_known_nonexistent (DBusHeader    *header, +                                      int            field) +{ +  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + +  return (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT); +} + +/** + * Writes a struct of { byte, variant } with the given basic type. + * + * @param writer the writer (should be ready to write a struct) + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @returns #FALSE if no memory + */ +static dbus_bool_t +write_basic_field (DBusTypeWriter *writer, +                   int             field, +                   int             type, +                   const void     *value) +{ +  DBusTypeWriter sub; +  DBusTypeWriter variant; +  int start; +  int padding; +  unsigned char field_byte; +  DBusString contained_type; +  char buf[2]; + +  start = writer->value_pos; +  padding = _dbus_string_get_length (writer->value_str) - start; + +  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, +                                  NULL, 0, &sub)) +    goto append_failed; + +  field_byte = field; +  if (!_dbus_type_writer_write_basic (&sub, DBUS_TYPE_BYTE, +                                      &field_byte)) +    goto append_failed; + +  buf[0] = type; +  buf[1] = '\0'; +  _dbus_string_init_const_len (&contained_type, buf, 1); + +  if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_VARIANT, +                                  &contained_type, 0, &variant)) +    goto append_failed; + +  if (!_dbus_type_writer_write_basic (&variant, type, value)) +    goto append_failed; + +  if (!_dbus_type_writer_unrecurse (&sub, &variant)) +    goto append_failed; + +  if (!_dbus_type_writer_unrecurse (writer, &sub)) +    goto append_failed; + +  return TRUE; + + append_failed: +  _dbus_string_delete (writer->value_str, +                       start, +                       _dbus_string_get_length (writer->value_str) - start - padding); +  return FALSE; +} + +/** + * Sets a struct of { byte, variant } with the given basic type. + * + * @param reader the reader (should be iterating over the array pointing at the field to set) + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @param realign_root where to realign from + * @returns #FALSE if no memory + */ +static dbus_bool_t +set_basic_field (DBusTypeReader       *reader, +                 int                   field, +                 int                   type, +                 const void           *value, +                 const DBusTypeReader *realign_root) +{ +  DBusTypeReader sub; +  DBusTypeReader variant; +  unsigned char v_BYTE; + +  _dbus_type_reader_recurse (reader, &sub); + +  _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); +#ifndef DBUS_DISABLE_ASSERT +  _dbus_type_reader_read_basic (&sub, &v_BYTE); +  _dbus_assert (((int) v_BYTE) == field); +#endif + +  if (!_dbus_type_reader_next (&sub)) +    _dbus_assert_not_reached ("no variant field?"); + +  _dbus_type_reader_recurse (&sub, &variant); +  _dbus_assert (_dbus_type_reader_get_current_type (&variant) == type); + +  if (!_dbus_type_reader_set_basic (&variant, value, realign_root)) +    return FALSE; + +  return TRUE; +} + +/** + * Gets the type of the message. + * + * @param header the header + * @returns the type + */ +int +_dbus_header_get_message_type (DBusHeader *header) +{ +  int type; + +  type = _dbus_string_get_byte (&header->data, TYPE_OFFSET); +  _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); + +  return type; +} + +/** + * Sets the serial number of a header.  This can only be done once on + * a header. + * + * @param header the header + * @param serial the serial + */ +void +_dbus_header_set_serial (DBusHeader    *header, +                         dbus_uint32_t  serial) +{ +  /* we use this function to set the serial on outgoing +   * messages, and to reset the serial in dbus_message_copy; +   * this assertion should catch a double-set on outgoing. +   */ +  _dbus_assert (_dbus_header_get_serial (header) == 0 || +                serial == 0); + +  _dbus_marshal_set_uint32 (&header->data, +                            SERIAL_OFFSET, +			    serial, +                            header->byte_order); +} + +/** + * See dbus_message_get_serial() + * + * @param header the header + * @returns the client serial + */ +dbus_uint32_t +_dbus_header_get_serial (DBusHeader *header) +{ +  return _dbus_marshal_read_uint32 (&header->data, +                                    SERIAL_OFFSET, +                                    header->byte_order, +                                    NULL); +} + +/** + * Re-initializes a header that was previously initialized and never + * freed.  After this, to make the header valid you have to call + * _dbus_header_create(). + * + * @param header header to re-initialize + * @param byte_order byte order of the header + */ +void +_dbus_header_reinit (DBusHeader *header, +                     int         byte_order) +{ +  _dbus_string_set_length (&header->data, 0); + +  header->byte_order = byte_order; +  header->padding = 0; + +  _dbus_header_cache_invalidate_all (header); +} + +/** + * Initializes a header, but doesn't prepare it for use; + * to make the header valid, you have to call _dbus_header_create(). + * + * @param header header to initialize + * @param byte_order byte order of the header + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_init (DBusHeader *header, +                   int         byte_order) +{ +  if (!_dbus_string_init_preallocated (&header->data, 32)) +    return FALSE; + +  _dbus_header_reinit (header, byte_order); + +  return TRUE; +} + +/** + * Frees a header. + * + * @param header the header + */ +void +_dbus_header_free (DBusHeader *header) +{ +  _dbus_string_free (&header->data); +} + +/** + * Initializes dest with a copy of the given header. + * Resets the message serial to 0 on the copy. + * + * @param header header to copy + * @param dest destination for copy + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_copy (const DBusHeader *header, +                   DBusHeader       *dest) +{ +  *dest = *header; + +  if (!_dbus_string_init_preallocated (&dest->data, +                                       _dbus_string_get_length (&header->data))) +    return FALSE; + +  if (!_dbus_string_copy (&header->data, 0, &dest->data, 0)) +    { +      _dbus_string_free (&dest->data); +      return FALSE; +    } + +  /* Reset the serial */ +  _dbus_header_set_serial (dest, 0); + +  return TRUE; +} + +/** + * Fills in the primary fields of the header, so the header is ready + * for use. #NULL may be specified for some or all of the fields to + * avoid adding those fields. Some combinations of fields don't make + * sense, and passing them in will trigger an assertion failure. + * + * @param header the header + * @param message_type the message type + * @param destination service field or #NULL + * @param path path field or #NULL + * @param interface interface field or #NULL + * @param member member field or #NULL + * @param error_name error name or #NULL + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_create (DBusHeader  *header, +                     int          message_type, +                     const char  *destination, +                     const char  *path, +                     const char  *interface, +                     const char  *member, +                     const char  *error_name) +{ +  unsigned char v_BYTE; +  dbus_uint32_t v_UINT32; +  DBusTypeWriter writer; +  DBusTypeWriter array; + +  _dbus_assert ((interface && member) || +                (error_name) || +                !(interface || member || error_name)); +  _dbus_assert (_dbus_string_get_length (&header->data) == 0); + +  if (!reserve_header_padding (header)) +    return FALSE; + +  _dbus_type_writer_init_values_only (&writer, header->byte_order, +                                      &_dbus_header_signature_str, 0, +                                      &header->data, +                                      HEADER_END_BEFORE_PADDING (header)); + +  v_BYTE = header->byte_order; +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, +                                      &v_BYTE)) +    goto oom; + +  v_BYTE = message_type; +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, +                                      &v_BYTE)) +    goto oom; + +  v_BYTE = 0; /* flags */ +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, +                                      &v_BYTE)) +    goto oom; + +  v_BYTE = DBUS_MAJOR_PROTOCOL_VERSION; +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, +                                      &v_BYTE)) +    goto oom; + +  v_UINT32 = 0; /* body length */ +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, +                                      &v_UINT32)) +    goto oom; + +  v_UINT32 = 0; /* serial */ +  if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, +                                      &v_UINT32)) +    goto oom; + +  if (!_dbus_type_writer_recurse (&writer, DBUS_TYPE_ARRAY, +                                  &_dbus_header_signature_str, +                                  FIELDS_ARRAY_SIGNATURE_OFFSET, +                                  &array)) +    goto oom; + +  /* Marshal all the fields (Marshall Fields?) */ + +  if (path != NULL) +    { +      if (!write_basic_field (&array, +                              DBUS_HEADER_FIELD_PATH, +                              DBUS_TYPE_OBJECT_PATH, +                              &path)) +        goto oom; +    } + +  if (destination != NULL) +    { +      if (!write_basic_field (&array, +                              DBUS_HEADER_FIELD_DESTINATION, +                              DBUS_TYPE_STRING, +                              &destination)) +        goto oom; +    } + +  if (interface != NULL) +    { +      if (!write_basic_field (&array, +                              DBUS_HEADER_FIELD_INTERFACE, +                              DBUS_TYPE_STRING, +                              &interface)) +        goto oom; +    } + +  if (member != NULL) +    { +      if (!write_basic_field (&array, +                              DBUS_HEADER_FIELD_MEMBER, +                              DBUS_TYPE_STRING, +                              &member)) +        goto oom; +    } + +  if (error_name != NULL) +    { +      if (!write_basic_field (&array, +                              DBUS_HEADER_FIELD_ERROR_NAME, +                              DBUS_TYPE_STRING, +                              &error_name)) +        goto oom; +    } + +  if (!_dbus_type_writer_unrecurse (&writer, &array)) +    goto oom; + +  correct_header_padding (header); + +  return TRUE; + + oom: +  _dbus_string_delete (&header->data, 0, +                       _dbus_string_get_length (&header->data) - header->padding); +  correct_header_padding (header); + +  return FALSE; +} + +/** + * Given data long enough to contain the length of the message body + * and the fields array, check whether the data is long enough to + * contain the entire message (assuming the claimed lengths are + * accurate). Also checks that the lengths are in sanity parameters. + * + * @param validity return location for why the data is invalid if it is + * @param byte_order return location for byte order + * @param fields_array_len return location for claimed fields array length + * @param header_len return location for claimed header length + * @param body_len return location for claimed body length + * @param str the data + * @param start start of data, 8-aligned + * @param len length of data + * @returns #TRUE if the data is long enough for the claimed length, and the lengths were valid + */ +dbus_bool_t +_dbus_header_have_message_untrusted (int                max_message_length, +                                     DBusValidity      *validity, +                                     int               *byte_order, +                                     int               *fields_array_len, +                                     int               *header_len, +                                     int               *body_len, +                                     const DBusString  *str, +                                     int                start, +                                     int                len) + +{ +  dbus_uint32_t header_len_unsigned; +  dbus_uint32_t fields_array_len_unsigned; +  dbus_uint32_t body_len_unsigned; + +  _dbus_assert (start >= 0); +  _dbus_assert (start < _DBUS_INT_MAX / 2); +  _dbus_assert (len >= 0); + +  _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); + +  *byte_order = _dbus_string_get_byte (str, start + BYTE_ORDER_OFFSET); + +  if (*byte_order != DBUS_LITTLE_ENDIAN && *byte_order != DBUS_BIG_ENDIAN) +    { +      *validity = DBUS_INVALID_BAD_BYTE_ORDER; +      return FALSE; +    } + +  _dbus_assert (FIELDS_ARRAY_LENGTH_OFFSET + 4 <= len); +  fields_array_len_unsigned = _dbus_marshal_read_uint32 (str, start + FIELDS_ARRAY_LENGTH_OFFSET, +                                                         *byte_order, NULL); + +  if (fields_array_len_unsigned > (unsigned) max_message_length) +    { +      *validity = DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH; +      return FALSE; +    } + +  _dbus_assert (BODY_LENGTH_OFFSET + 4 < len); +  body_len_unsigned = _dbus_marshal_read_uint32 (str, start + BODY_LENGTH_OFFSET, +                                                 *byte_order, NULL); + +  if (body_len_unsigned > (unsigned) max_message_length) +    { +      *validity = DBUS_INVALID_INSANE_BODY_LENGTH; +      return FALSE; +    } + +  header_len_unsigned = FIRST_FIELD_OFFSET + fields_array_len_unsigned; +  header_len_unsigned = _DBUS_ALIGN_VALUE (header_len_unsigned, 8); + +  /* overflow should be impossible since the lengths aren't allowed to +   * be huge. +   */ +  _dbus_assert (max_message_length < _DBUS_INT_MAX / 2); +  if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length) +    { +      *validity = DBUS_INVALID_MESSAGE_TOO_LONG; +      return FALSE; +    } + +  _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT_MAX); +  _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT_MAX); +  _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT_MAX); + +  *body_len = body_len_unsigned; +  *fields_array_len = fields_array_len_unsigned; +  *header_len = header_len_unsigned; + +  *validity = DBUS_VALID; + +  _dbus_verbose ("have %d bytes, need body %u + header %u = %u\n", +                 len, body_len_unsigned, header_len_unsigned, +                 body_len_unsigned + header_len_unsigned); + +  return (body_len_unsigned + header_len_unsigned) <= (unsigned) len; +} + +static DBusValidity +check_mandatory_fields (DBusHeader *header) +{ +#define REQUIRE_FIELD(name) do { if (header->fields[DBUS_HEADER_FIELD_##name].value_pos < 0) return DBUS_INVALID_MISSING_##name; } while (0) + +  switch (_dbus_header_get_message_type (header)) +    { +    case DBUS_MESSAGE_TYPE_SIGNAL: +      REQUIRE_FIELD (INTERFACE); +      /* FALL THRU - signals also require the path and member */ +    case DBUS_MESSAGE_TYPE_METHOD_CALL: +      REQUIRE_FIELD (PATH); +      REQUIRE_FIELD (MEMBER); +      break; +    case DBUS_MESSAGE_TYPE_ERROR: +      REQUIRE_FIELD (ERROR_NAME); +      REQUIRE_FIELD (REPLY_SERIAL); +      break; +    case DBUS_MESSAGE_TYPE_METHOD_RETURN: +      REQUIRE_FIELD (REPLY_SERIAL); +      break; +    default: +      /* other message types allowed but ignored */ +      break; +    } + +  return DBUS_VALID; +} + +static DBusValidity +load_and_validate_field (DBusHeader     *header, +                         int             field, +                         DBusTypeReader *variant_reader) +{ +  int type; +  int expected_type; +  const DBusString *value_str; +  int value_pos; +  dbus_uint32_t v_UINT32; +  int bad_string_code; +  dbus_bool_t (* string_validation_func) (const DBusString *str, +                                          int start, int len); + +  /* Supposed to have been checked already */ +  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); +  _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); + +  /* Before we can cache a field, we need to know it has the right type */ +  type = _dbus_type_reader_get_current_type (variant_reader); + +  _dbus_assert (_dbus_header_field_types[field].code == field); + +  expected_type = EXPECTED_TYPE_OF_FIELD (field); +  if (type != expected_type) +    { +      _dbus_verbose ("Field %d should have type %d but has %d\n", +                     field, expected_type, type); +      return DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE; +    } + +  /* If the field was provided twice, we aren't happy */ +  if (header->fields[field].value_pos >= 0) +    { +      _dbus_verbose ("Header field %d seen a second time\n", field); +      return DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE; +    } + +  /* Now we can cache and look at the field content */ +  _dbus_verbose ("initially caching field %d\n", field); +  _dbus_header_cache_one (header, field, variant_reader); + +  string_validation_func = NULL; + +  /* make compiler happy that all this is initialized */ +  v_UINT32 = 0; +  value_str = NULL; +  value_pos = -1; +  bad_string_code = DBUS_VALID; + +  if (expected_type == DBUS_TYPE_UINT32) +    { +      _dbus_header_get_field_basic (header, field, expected_type, +                                    &v_UINT32); +    } +  else if (expected_type == DBUS_TYPE_STRING || +           expected_type == DBUS_TYPE_OBJECT_PATH || +           expected_type == DBUS_TYPE_SIGNATURE) +    { +      _dbus_header_get_field_raw (header, field, +                                  &value_str, &value_pos); +    } +  else +    { +      _dbus_assert_not_reached ("none of the known fields should have this type"); +    } + +  switch (field) +    { +    case DBUS_HEADER_FIELD_DESTINATION: +      string_validation_func = _dbus_validate_service; +      bad_string_code = DBUS_INVALID_BAD_DESTINATION; +      break; +    case DBUS_HEADER_FIELD_INTERFACE: +      string_validation_func = _dbus_validate_interface; +      bad_string_code = DBUS_INVALID_BAD_INTERFACE; + +      if (_dbus_string_equal_substring (&_dbus_local_interface_str, +                                        0, +                                        _dbus_string_get_length (&_dbus_local_interface_str), +                                        value_str, value_pos)) +        { +          _dbus_verbose ("Message is on the local interface\n"); +          return DBUS_INVALID_USES_LOCAL_INTERFACE; +        } +      break; + +    case DBUS_HEADER_FIELD_MEMBER: +      string_validation_func = _dbus_validate_member; +      bad_string_code = DBUS_INVALID_BAD_MEMBER; +      break; + +    case DBUS_HEADER_FIELD_ERROR_NAME: +      string_validation_func = _dbus_validate_error_name; +      bad_string_code = DBUS_INVALID_BAD_ERROR_NAME; +      break; + +    case DBUS_HEADER_FIELD_SENDER: +      string_validation_func = _dbus_validate_service; +      bad_string_code = DBUS_INVALID_BAD_SENDER; +      break; + +    case DBUS_HEADER_FIELD_PATH: +      /* OBJECT_PATH was validated generically due to its type */ +      string_validation_func = NULL; + +      _dbus_verbose ("value_str %p value_pos %d value_str_len %d\n", +                     value_str, value_pos, +                     _dbus_string_get_length (value_str)); +      if (_dbus_string_equal_substring (&_dbus_local_path_str, +                                        0, +                                        _dbus_string_get_length (&_dbus_local_path_str), +                                        value_str, value_pos)) +        { +          _dbus_verbose ("Message is from the local path\n"); +          return DBUS_INVALID_USES_LOCAL_PATH; +        } +      break; + +    case DBUS_HEADER_FIELD_REPLY_SERIAL: +      /* Can't be 0 */ +      if (v_UINT32 == 0) +        { +          return DBUS_INVALID_BAD_SERIAL; +        } +      break; + +    case DBUS_HEADER_FIELD_SIGNATURE: +      /* SIGNATURE validated generically due to its type */ +      string_validation_func = NULL; +      break; + +    default: +      _dbus_assert_not_reached ("unknown field shouldn't be seen here"); +      break; +    } + +  if (string_validation_func) +    { +      dbus_uint32_t len; + +      _dbus_assert (bad_string_code != DBUS_VALID); + +      len = _dbus_marshal_read_uint32 (value_str, value_pos, +                                       header->byte_order, NULL); + +      if (!(*string_validation_func) (value_str, value_pos + 4, len)) +        return bad_string_code; +    } + +  return DBUS_VALID; +} + +/** + * Creates a message header from untrusted data. The return value + * is #TRUE if there was enough memory and the data was valid. If it + * returns #TRUE, the header will be created. If it returns #FALSE + * and *validity == #DBUS_VALID, then there wasn't enough memory.  If + * it returns #FALSE and *validity != #DBUS_VALID then the data was + * invalid. + * + * The byte_order, fields_array_len, and body_len args should be from + * _dbus_header_have_message_untrusted(). Validation performed in + * _dbus_header_have_message_untrusted() is assumed to have been + * already done. + * + * @param header the header (must be initialized) + * @param validity return location for invalidity reason + * @param byte_order byte order from header + * @param fields_array_len claimed length of fields array + * @param body_len claimed length of body + * @param header_len claimed length of header + * @param str a string + * @param start start of header, 8-aligned + * @param len length of string to look at + * @returns #FALSE if no memory or data was invalid, #TRUE otherwise + */ +dbus_bool_t +_dbus_header_load_untrusted (DBusHeader       *header, +                             DBusValidity     *validity, +                             int               byte_order, +                             int               fields_array_len, +                             int               header_len, +                             int               body_len, +                             const DBusString *str, +                             int               start, +                             int               len) +{ +  int leftover; +  DBusValidity v; +  DBusTypeReader reader; +  DBusTypeReader array_reader; +  unsigned char v_byte; +  dbus_uint32_t v_uint32; +  dbus_uint32_t serial; +  int padding_start; +  int padding_len; +  int i; + +  _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); +  _dbus_assert (header_len <= len); +  _dbus_assert (_dbus_string_get_length (&header->data) == 0); + +  if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0)) +    { +      _dbus_verbose ("Failed to copy buffer into new header\n"); +      *validity = DBUS_VALID; +      return FALSE; +    } + +  v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0, +                                       byte_order, +                                       &leftover, +                                       str, start, len); + +  if (v != DBUS_VALID) +    { +      *validity = v; +      goto invalid; +    } + +  _dbus_assert (leftover < len); + +  padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len); +  padding_start = start + FIRST_FIELD_OFFSET + fields_array_len; +  _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8)); +  _dbus_assert (start + header_len == padding_start + padding_len); + +  if (!_dbus_string_validate_nul (str, padding_start, padding_len)) +    { +      *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; +      goto invalid; +    } + +  header->padding = padding_len; + +  /* We now know the data is well-formed, but we have to check that +   * it's valid. +   */ + +  _dbus_type_reader_init (&reader, +                          byte_order, +                          &_dbus_header_signature_str, 0, +                          str, start); + +  /* BYTE ORDER */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET); +  _dbus_type_reader_read_basic (&reader, &v_byte); +  _dbus_type_reader_next (&reader); + +  _dbus_assert (v_byte == byte_order); + +  /* MESSAGE TYPE */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET); +  _dbus_type_reader_read_basic (&reader, &v_byte); +  _dbus_type_reader_next (&reader); + +  /* unknown message types are supposed to be ignored, so only validation here is +   * that it isn't invalid +   */ +  if (v_byte == DBUS_MESSAGE_TYPE_INVALID) +    { +      *validity = DBUS_INVALID_BAD_MESSAGE_TYPE; +      goto invalid; +    } + +  /* FLAGS */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET); +  _dbus_type_reader_read_basic (&reader, &v_byte); +  _dbus_type_reader_next (&reader); + +  /* unknown flags should be ignored */ + +  /* PROTOCOL VERSION */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET); +  _dbus_type_reader_read_basic (&reader, &v_byte); +  _dbus_type_reader_next (&reader); + +  if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION) +    { +      *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION; +      goto invalid; +    } + +  /* BODY LENGTH */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET); +  _dbus_type_reader_read_basic (&reader, &v_uint32); +  _dbus_type_reader_next (&reader); + +  _dbus_assert (body_len == (signed) v_uint32); + +  /* SERIAL */ +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET); +  _dbus_type_reader_read_basic (&reader, &serial); +  _dbus_type_reader_next (&reader); + +  if (serial == 0) +    { +      *validity = DBUS_INVALID_BAD_SERIAL; +      goto invalid; +    } + +  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY); +  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET); + +  _dbus_type_reader_recurse (&reader, &array_reader); +  while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID) +    { +      DBusTypeReader struct_reader; +      DBusTypeReader variant_reader; +      unsigned char field_code; + +      _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT); + +      _dbus_type_reader_recurse (&array_reader, &struct_reader); + +      _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE); +      _dbus_type_reader_read_basic (&struct_reader, &field_code); +      _dbus_type_reader_next (&struct_reader); + +      if (field_code == DBUS_HEADER_FIELD_INVALID) +        { +          _dbus_verbose ("invalid header field code\n"); +          *validity = DBUS_INVALID_HEADER_FIELD_CODE; +          goto invalid; +        } + +      if (field_code > DBUS_HEADER_FIELD_LAST) +        { +          _dbus_verbose ("unknown header field code %d, skipping\n", +                         field_code); +          goto next_field; +        } + +      _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT); +      _dbus_type_reader_recurse (&struct_reader, &variant_reader); + +      v = load_and_validate_field (header, field_code, &variant_reader); +      if (v != DBUS_VALID) +        { +          _dbus_verbose ("Field %d was invalid\n", field_code); +          *validity = v; +          goto invalid; +        } + +    next_field: +      _dbus_type_reader_next (&array_reader); +    } + +  /* Anything we didn't fill in is now known not to exist */ +  i = 0; +  while (i <= DBUS_HEADER_FIELD_LAST) +    { +      if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) +        header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; +      ++i; +    } + +  v = check_mandatory_fields (header); +  if (v != DBUS_VALID) +    { +      _dbus_verbose ("Mandatory fields were missing, code %d\n", v); +      *validity = v; +      goto invalid; +    } + +  *validity = DBUS_VALID; +  return TRUE; + + invalid: +  _dbus_string_set_length (&header->data, 0); +  return FALSE; +} + +/** + * Fills in the correct body length. + * + * @param header the header + * @param body_len the length of the body + */ +void +_dbus_header_update_lengths (DBusHeader *header, +                             int         body_len) +{ +  _dbus_marshal_set_uint32 (&header->data, +                            BODY_LENGTH_OFFSET, +                            body_len, +                            header->byte_order); +} + +static dbus_bool_t +find_field_for_modification (DBusHeader     *header, +                             int             field, +                             DBusTypeReader *reader, +                             DBusTypeReader *realign_root) +{ +  dbus_bool_t retval; + +  retval = FALSE; + +  _dbus_type_reader_init (realign_root, +                          header->byte_order, +                          &_dbus_header_signature_str, +                          FIELDS_ARRAY_SIGNATURE_OFFSET, +                          &header->data, +                          FIELDS_ARRAY_LENGTH_OFFSET); + +  _dbus_type_reader_recurse (realign_root, reader); + +  while (_dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID) +    { +      DBusTypeReader sub; +      unsigned char field_code; + +      _dbus_type_reader_recurse (reader, &sub); + +      _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); +      _dbus_type_reader_read_basic (&sub, &field_code); + +      if (field_code == (unsigned) field) +        { +          _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_STRUCT); +          retval = TRUE; +          goto done; +        } + +      _dbus_type_reader_next (reader); +    } + + done: +  return retval; +} + +/** + * Sets the value of a field with basic type. If the value is a string + * value, it isn't allowed to be #NULL. If the field doesn't exist, + * it will be created. + * + * @param header the header + * @param field the field to set + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_header_set_field_basic (DBusHeader       *header, +                              int               field, +                              int               type, +                              const void       *value) +{ +  _dbus_return_val_if_fail (field <= DBUS_HEADER_FIELD_LAST, FALSE); + +  if (!reserve_header_padding (header)) +    return FALSE; + +  /* If the field exists we set, otherwise we append */ +  if (_dbus_header_cache_check (header, field)) +    { +      DBusTypeReader reader; +      DBusTypeReader realign_root; + +      if (!find_field_for_modification (header, field, +                                        &reader, &realign_root)) +        _dbus_assert_not_reached ("field was marked present in cache but wasn't found"); + +      if (!set_basic_field (&reader, field, type, value, &realign_root)) +        return FALSE; +    } +  else +    { +      DBusTypeWriter writer; +      DBusTypeWriter array; + +      _dbus_type_writer_init_values_only (&writer, +                                          header->byte_order, +                                          &_dbus_header_signature_str, +                                          FIELDS_ARRAY_SIGNATURE_OFFSET, +                                          &header->data, +                                          FIELDS_ARRAY_LENGTH_OFFSET); + +      /* recurse into array without creating a new length, and jump to +       * end of array. +       */ +      if (!_dbus_type_writer_append_array (&writer, +                                           &_dbus_header_signature_str, +                                           FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET, +                                           &array)) +        _dbus_assert_not_reached ("recurse into ARRAY should not have used memory"); + +      _dbus_assert (array.u.array.len_pos == FIELDS_ARRAY_LENGTH_OFFSET); +      _dbus_assert (array.u.array.start_pos == FIRST_FIELD_OFFSET); +      _dbus_assert (array.value_pos == HEADER_END_BEFORE_PADDING (header)); + +      if (!write_basic_field (&array, +                              field, type, value)) +        return FALSE; + +      if (!_dbus_type_writer_unrecurse (&writer, &array)) +        _dbus_assert_not_reached ("unrecurse from ARRAY should not have used memory"); +    } + +  correct_header_padding (header); + +  /* We could be smarter about this (only invalidate fields after the +   * one we modified, or even only if the one we modified changed +   * length). But this hack is a start. +   */ +  _dbus_header_cache_invalidate_all (header); + +  return TRUE; +} + +/** + * Gets the value of a field with basic type. If the field + * doesn't exist, returns #FALSE, otherwise returns #TRUE. + * + * @param header the header + * @param field the field to get + * @param type the type of the value + * @param value the value as for _dbus_marshal_read_basic() + * @returns #FALSE if the field doesn't exist + */ +dbus_bool_t +_dbus_header_get_field_basic (DBusHeader    *header, +                              int            field, +                              int            type, +                              void          *value) +{ +  _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); +  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); +  _dbus_assert (_dbus_header_field_types[field].code == field); +  /* in light of this you might ask why the type is passed in; +   * the only rationale I can think of is so the caller has +   * to specify its expectation and breaks if we change it +   */ +  _dbus_assert (type == EXPECTED_TYPE_OF_FIELD (field)); + +  if (!_dbus_header_cache_check (header, field)) +    return FALSE; + +  _dbus_assert (header->fields[field].value_pos >= 0); + +  _dbus_marshal_read_basic (&header->data, +                            header->fields[field].value_pos, +                            type, value, header->byte_order, +                            NULL); + +  return TRUE; +} + +/** + * Gets the raw marshaled data for a field. If the field doesn't + * exist, returns #FALSE, otherwise returns #TRUE.  Returns the start + * of the marshaled data, i.e. usually the byte where the length + * starts (for strings and arrays) or for basic types just the value + * itself. + * + * @param header the header + * @param field the field to get + * @param str return location for the data string + * @param pos return location for start of field value + * @returns #FALSE if the field doesn't exist + */ +dbus_bool_t +_dbus_header_get_field_raw (DBusHeader        *header, +                            int                field, +                            const DBusString **str, +                            int               *pos) +{ +  if (!_dbus_header_cache_check (header, field)) +    return FALSE; + +  if (str) +    *str = &header->data; +  if (pos) +    *pos = header->fields[field].value_pos; + +  return TRUE; +} + +/** + * Deletes a field, if it exists. + * + * @param header the header + * @param field the field to delete + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_header_delete_field (DBusHeader *header, +                           int         field) +{ +  DBusTypeReader reader; +  DBusTypeReader realign_root; + +  if (_dbus_header_cache_known_nonexistent (header, field)) +    return TRUE; /* nothing to do */ + +  /* Scan to the field we want, delete and realign, reappend +   * padding. Field may turn out not to exist. +   */ +  if (!find_field_for_modification (header, field, +                                    &reader, &realign_root)) +    return TRUE; /* nothing to do */ + +  if (!reserve_header_padding (header)) +    return FALSE; + +  if (!_dbus_type_reader_delete (&reader, +                                 &realign_root)) +    return FALSE; + +  correct_header_padding (header); + +  _dbus_header_cache_invalidate_all (header); + +  _dbus_assert (!_dbus_header_cache_check (header, field)); /* Expensive assertion ... */ + +  return TRUE; +} + +/** + * Toggles a message flag bit, turning on the bit if value = TRUE and + * flipping it off if value = FALSE. + * + * @param header the header + * @param flag the message flag to toggle + * @param value toggle on or off + */ +void +_dbus_header_toggle_flag (DBusHeader   *header, +                          dbus_uint32_t flag, +                          dbus_bool_t   value) +{ +  unsigned char *flags_p; + +  flags_p = _dbus_string_get_data_len (&header->data, FLAGS_OFFSET, 1); + +  if (value) +    *flags_p |= flag; +  else +    *flags_p &= ~flag; +} + +/** + * Gets a message flag bit, returning TRUE if the bit is set. + * + * @param header the header + * @param flag the message flag to get + * @returns #TRUE if the flag is set + */ +dbus_bool_t +_dbus_header_get_flag (DBusHeader   *header, +                       dbus_uint32_t flag) +{ +  const unsigned char *flags_p; + +  flags_p = _dbus_string_get_const_data_len (&header->data, FLAGS_OFFSET, 1); + +  return (*flags_p & flag) != 0; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include <stdio.h> + +dbus_bool_t +_dbus_marshal_header_test (void) +{ + +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-header.h b/dbus/dbus-marshal-header.h new file mode 100644 index 00000000..32bf51eb --- /dev/null +++ b/dbus/dbus-marshal-header.h @@ -0,0 +1,128 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-marshal-header.h  Managing marshaling/demarshaling of message headers + * + * 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_MARSHAL_HEADER_H +#define DBUS_MARSHAL_HEADER_H + +#include <config.h> +#include <dbus/dbus-marshal-basic.h> +#include <dbus/dbus-marshal-validate.h> + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +typedef struct DBusHeader      DBusHeader; +typedef struct DBusHeaderField DBusHeaderField; + +#define _DBUS_HEADER_FIELD_VALUE_UNKNOWN -1 +#define _DBUS_HEADER_FIELD_VALUE_NONEXISTENT -2 + +/** + * Cached information about a header field in the message + */ +struct DBusHeaderField +{ +  int            value_pos; /**< Position of field value, or -1/-2 */ +}; + +struct DBusHeader +{ +  DBusString data; /**< Header network data, stored +                    * separately from body so we can +                    * independently realloc it. +                    */ + +  DBusHeaderField fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location +                                                       * of each field in header +                                                       */ + +  dbus_uint32_t padding : 3;        /**< bytes of alignment in header */ +  dbus_uint32_t byte_order : 8;     /**< byte order of header */ +}; + +dbus_bool_t   _dbus_header_init                   (DBusHeader        *header, +                                                   int                byte_order); +void          _dbus_header_free                   (DBusHeader        *header); +void          _dbus_header_reinit                 (DBusHeader        *header, +                                                   int                byte_order); +dbus_bool_t   _dbus_header_create                 (DBusHeader        *header, +                                                   int                type, +                                                   const char        *destination, +                                                   const char        *path, +                                                   const char        *interface, +                                                   const char        *member, +                                                   const char        *error_name); +dbus_bool_t   _dbus_header_copy                   (const DBusHeader  *header, +                                                   DBusHeader        *dest); +int           _dbus_header_get_message_type       (DBusHeader        *header); +void          _dbus_header_set_serial             (DBusHeader        *header, +                                                   dbus_uint32_t      serial); +dbus_uint32_t _dbus_header_get_serial             (DBusHeader        *header); +void          _dbus_header_update_lengths         (DBusHeader        *header, +                                                   int                body_len); +dbus_bool_t   _dbus_header_set_field_basic        (DBusHeader        *header, +                                                   int                field, +                                                   int                type, +                                                   const void        *value); +dbus_bool_t   _dbus_header_get_field_basic        (DBusHeader        *header, +                                                   int                field, +                                                   int                type, +                                                   void              *value); +dbus_bool_t   _dbus_header_get_field_raw          (DBusHeader        *header, +                                                   int                field, +                                                   const DBusString **str, +                                                   int               *pos); +dbus_bool_t   _dbus_header_delete_field           (DBusHeader        *header, +                                                   int                field); +void          _dbus_header_toggle_flag            (DBusHeader        *header, +                                                   dbus_uint32_t      flag, +                                                   dbus_bool_t        value); +dbus_bool_t   _dbus_header_get_flag               (DBusHeader        *header, +                                                   dbus_uint32_t      flag); +dbus_bool_t   _dbus_header_ensure_signature       (DBusHeader        *header, +                                                   DBusString       **type_str, +                                                   int               *type_pos); +dbus_bool_t   _dbus_header_have_message_untrusted (int                max_message_length, +                                                   DBusValidity      *validity, +                                                   int               *byte_order, +                                                   int               *fields_array_len, +                                                   int               *header_len, +                                                   int               *body_len, +                                                   const DBusString  *str, +                                                   int                start, +                                                   int                len); +dbus_bool_t   _dbus_header_load_untrusted         (DBusHeader        *header, +                                                   DBusValidity      *validity, +                                                   int                byte_order, +                                                   int                fields_array_len, +                                                   int                header_len, +                                                   int                body_len, +                                                   const DBusString  *str, +                                                   int                start, +                                                   int                len); + + + + +#endif /* DBUS_MARSHAL_HEADER_H */ diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index a3ef0217..3b2ce91d 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -29,7 +29,29 @@   * @addtogroup DBusMarshal   * @{   */ -#define RECURSIVE_MARSHAL_TRACE 0 +#define RECURSIVE_MARSHAL_READ_TRACE  0 +#define RECURSIVE_MARSHAL_WRITE_TRACE 0 + +static void +free_fixups (DBusList **fixups) +{ +  DBusList *link; + +  link = _dbus_list_get_first_link (fixups); +  while (link != NULL) +    { +      DBusList *next; + +      next = _dbus_list_get_next_link (fixups, link); + +      dbus_free (link->data); +      _dbus_list_free_link (link); + +      link = next; +    } + +  *fixups = NULL; +}  static void  apply_and_free_fixups (DBusList      **fixups, @@ -37,7 +59,7 @@ apply_and_free_fixups (DBusList      **fixups,  {    DBusList *link; -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE    if (*fixups)      _dbus_verbose (" %d FIXUPS to apply\n",                     _dbus_list_get_length (fixups)); @@ -56,7 +78,7 @@ apply_and_free_fixups (DBusList      **fixups,            f = link->data; -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE            _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",                           reader, f->len_pos_in_reader, f->new_len,                           _dbus_marshal_read_uint32 (reader->value_str, @@ -198,8 +220,10 @@ array_reader_get_array_len (const DBusTypeReader *reader)                              reader->byte_order,                              NULL); +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("   reader %p len_pos %d array len %u len_offset %d\n",                   reader, len_pos, array_len, reader->array_len_offset); +#endif    _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8); @@ -230,7 +254,7 @@ array_reader_recurse (DBusTypeReader *sub,    _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */    sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("    type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",                   sub,                   sub->u.array.start_pos, @@ -262,7 +286,7 @@ variant_reader_recurse (DBusTypeReader *sub,    sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("    type reader %p variant containing '%s'\n",                   sub,                   _dbus_string_get_const_data_len (sub->type_str, @@ -345,14 +369,21 @@ base_reader_next (DBusTypeReader *reader,        {          DBusTypeReader sub; -        /* Recurse into the struct or variant */ -        _dbus_type_reader_recurse (reader, &sub); - -        /* Skip everything in this subreader */ -        while (_dbus_type_reader_next (&sub)) +        if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT) +          ; +        else            { -            /* nothing */; +            /* Recurse into the struct or variant */ +            _dbus_type_reader_recurse (reader, &sub); + +            /* Skip everything in this subreader */ +            while (_dbus_type_reader_next (&sub)) +              { +                /* nothing */; +              }            } +        if (!reader->klass->types_only) +          reader->value_pos = sub.value_pos;          /* Now we are at the end of this container; for variants, the           * subreader's type_pos is totally inapplicable (it's in the @@ -363,9 +394,6 @@ base_reader_next (DBusTypeReader *reader,            reader->type_pos += 1;          else            reader->type_pos = sub.type_pos; - -        if (!reader->klass->types_only) -          reader->value_pos = sub.value_pos;        }        break; @@ -435,7 +463,7 @@ array_reader_next (DBusTypeReader *reader,    end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",                   reader,                   reader->u.array.start_pos, @@ -487,7 +515,7 @@ array_reader_next (DBusTypeReader *reader,        break;      } -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",                   reader,                   reader->u.array.start_pos, @@ -602,7 +630,7 @@ _dbus_type_reader_init (DBusTypeReader    *reader,    reader_init (reader, byte_order, type_str, type_pos,                 value_str, value_pos); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -626,7 +654,7 @@ _dbus_type_reader_init_from_mark (DBusTypeReader     *reader,    if (reader->klass->init_from_mark)      (* reader->klass->init_from_mark) (reader, mark); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -643,7 +671,7 @@ _dbus_type_reader_init_types_only (DBusTypeReader    *reader,    reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,                 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -666,7 +694,7 @@ _dbus_type_reader_init_types_only_from_mark (DBusTypeReader     *reader,    if (reader->klass->init_from_mark)      (* reader->klass->init_from_mark) (reader, mark); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -714,6 +742,25 @@ _dbus_type_reader_get_current_type (const DBusTypeReader *reader)    return t;  } +int +_dbus_type_reader_get_array_type (const DBusTypeReader  *reader) +{ +  int element_type; + +  _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY); + +  element_type = first_type_in_signature (reader->type_str, +                                          reader->type_pos + 1); + +  return element_type; +} + +int +_dbus_type_reader_get_value_pos (const DBusTypeReader  *reader) +{ +  return reader->value_pos; +} +  dbus_bool_t  _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)  { @@ -723,7 +770,7 @@ _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)    _dbus_assert (!reader->klass->types_only);    /* reader is supposed to be at an array child */ -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE     _dbus_verbose ("checking array len at %d\n", reader->value_pos);  #endif @@ -733,13 +780,33 @@ _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)                               &array_len,                               reader->byte_order,                               NULL); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose (" ... array len = %d\n", array_len);  #endif    return array_len == 0;  } +/** + * Get the address of the marshaled value in the data being read.  The + * address may not be aligned; you have to align it to the type of the + * value you want to read. Most of the demarshal routines do this for + * you. + * + * @param reader the reader + * @param value_location the address of the marshaled value + */ +void +_dbus_type_reader_read_raw (const DBusTypeReader  *reader, +                            const unsigned char  **value_location) +{ +  _dbus_assert (!reader->klass->types_only); + +  *value_location = _dbus_string_get_const_data_len (reader->value_str, +                                                     reader->value_pos, +                                                     0); +} +  void  _dbus_type_reader_read_basic (const DBusTypeReader    *reader,                                void                    *value) @@ -757,7 +824,7 @@ _dbus_type_reader_read_basic (const DBusTypeReader    *reader,                              NULL); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -765,8 +832,9 @@ _dbus_type_reader_read_basic (const DBusTypeReader    *reader,  }  /** - * Reads an array of fixed-length basic values.  Does not work for - * arrays of string or container types. + * Reads a block of fixed-length basic values, from the current point + * in an array to the end of the array.  Does not work for arrays of + * string or container types.   *   * This function returns the array in-place; it does not make a copy,   * and it does not swap the bytes. @@ -775,11 +843,11 @@ _dbus_type_reader_read_basic (const DBusTypeReader    *reader,   * and the "value" argument should be a "const double**" and so on.   *   * @param reader the reader to read from - * @param value place to return the array + * @param value place to return the array values   * @param n_elements place to return number of array elements   */  void -_dbus_type_reader_read_fixed_array (const DBusTypeReader  *reader, +_dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,                                      void                  *value,                                      int                   *n_elements)  { @@ -787,6 +855,7 @@ _dbus_type_reader_read_fixed_array (const DBusTypeReader  *reader,    int end_pos;    int remaining_len;    int alignment; +  int total_len;    _dbus_assert (!reader->klass->types_only);    _dbus_assert (reader->klass == &array_reader_class); @@ -799,9 +868,19 @@ _dbus_type_reader_read_fixed_array (const DBusTypeReader  *reader,    alignment = _dbus_type_get_alignment (element_type); -  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); +  _dbus_assert (reader->value_pos >= reader->u.array.start_pos); + +  total_len = array_reader_get_array_len (reader); +  end_pos = reader->u.array.start_pos + total_len;    remaining_len = end_pos - reader->value_pos; +#if RECURSIVE_MARSHAL_READ_TRACE +  _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n", +                 end_pos, total_len, remaining_len, reader->value_pos); +#endif + +  _dbus_assert (remaining_len <= total_len); +    if (remaining_len == 0)      *(const DBusBasicValue**) value = NULL;    else @@ -813,7 +892,7 @@ _dbus_type_reader_read_fixed_array (const DBusTypeReader  *reader,    *n_elements = remaining_len / alignment;    _dbus_assert ((remaining_len % alignment) == 0); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); @@ -874,7 +953,7 @@ _dbus_type_reader_recurse (DBusTypeReader *reader,    (* sub->klass->recurse) (sub, reader); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",                   sub, sub->type_pos, sub->value_pos,                   _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0)); @@ -896,7 +975,7 @@ _dbus_type_reader_next (DBusTypeReader *reader)    t = _dbus_type_reader_get_current_type (reader); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), @@ -908,7 +987,7 @@ _dbus_type_reader_next (DBusTypeReader *reader)    (* reader->klass->next) (reader, t); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_READ_TRACE    _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), @@ -984,12 +1063,10 @@ replacement_block_init (ReplacementBlock *block,    if (!_dbus_string_init (&block->replacement))      return FALSE; -  /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 - -   * ALIGN_OFFSET is the padding to have the same align properties in +  /* % 8 is the padding to have the same align properties in     * our replacement string as we do at the position being replaced     */ -  block->padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8); -  _dbus_assert (block->padding >= 0); +  block->padding = reader->value_pos % 8;    if (!_dbus_string_lengthen (&block->replacement, block->padding))      goto oom; @@ -1017,6 +1094,10 @@ replacement_block_replace (ReplacementBlock     *block,    realign_reader = *realign_root; +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n", +                 &writer, _dbus_string_get_length (&block->replacement)); +#endif    _dbus_type_writer_init_values_only (&writer,                                        realign_reader.byte_order,                                        realign_reader.type_str, @@ -1024,6 +1105,12 @@ replacement_block_replace (ReplacementBlock     *block,                                        &block->replacement,                                        _dbus_string_get_length (&block->replacement)); +  _dbus_assert (realign_reader.value_pos <= reader->value_pos); + +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n", +                 realign_reader.value_pos, &writer, reader->value_pos); +#endif    fixups = NULL;    if (!_dbus_type_writer_write_reader_partial (&writer,                                                 &realign_reader, @@ -1033,14 +1120,15 @@ replacement_block_replace (ReplacementBlock     *block,                                                 &fixups))      goto oom; -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", padding, -                 _dbus_string_get_length (&block->replacement) - padding); -  _dbus_verbose_bytes_of_string (&block->replacement, padding, -                                 _dbus_string_get_length (&block->replacement) - padding); -  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d\n", -                 reader->value_pos, (int) (8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8)), -                 realign_reader.value_pos - reader->value_pos); +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding, +                 _dbus_string_get_length (&block->replacement) - block->padding); +  _dbus_verbose_bytes_of_string (&block->replacement, block->padding, +                                 _dbus_string_get_length (&block->replacement) - block->padding); +  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n", +                 reader->value_pos, reader->value_pos % 8, +                 realign_reader.value_pos - reader->value_pos, +                 realign_reader.value_pos);    _dbus_verbose_bytes_of_string (reader->value_str,                                   reader->value_pos,                                   realign_reader.value_pos - reader->value_pos); @@ -1063,6 +1151,7 @@ replacement_block_replace (ReplacementBlock     *block,   oom:    _dbus_string_set_length (&block->replacement, orig_len); +  free_fixups (&fixups);    return FALSE;  } @@ -1113,14 +1202,19 @@ reader_set_basic_variable_length (DBusTypeReader       *reader,      return FALSE;    /* Write the new basic value */ - +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n", +                 &writer, _dbus_string_get_length (&block.replacement)); +#endif    _dbus_type_writer_init_values_only (&writer,                                        reader->byte_order,                                        reader->type_str,                                        reader->type_pos,                                        &block.replacement,                                        _dbus_string_get_length (&block.replacement)); - +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer); +#endif    if (!_dbus_type_writer_write_basic (&writer, current_type, value))      goto out; @@ -1191,16 +1285,21 @@ _dbus_type_reader_set_basic (DBusTypeReader       *reader,    int current_type;    _dbus_assert (!reader->klass->types_only); +  _dbus_assert (reader->value_str == realign_root->value_str); +  _dbus_assert (reader->value_pos >= realign_root->value_pos);    current_type = _dbus_type_reader_get_current_type (reader); -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("  type reader %p set basic type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n", +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",                   reader, reader->type_pos, reader->value_pos,                   _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),                   realign_root,                   realign_root ? realign_root->value_pos : -1,                   _dbus_type_to_string (current_type)); +  _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos, +                                 _dbus_string_get_length (realign_root->value_str) - +                                 realign_root->value_pos);  #endif    _dbus_assert (_dbus_type_is_basic (current_type)); @@ -1325,7 +1424,7 @@ _dbus_type_writer_init (DBusTypeWriter *writer,    writer->type_pos_is_expectation = FALSE;    writer->enabled = TRUE; -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE    _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,                   writer->type_str ?                   _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : @@ -1334,6 +1433,58 @@ _dbus_type_writer_init (DBusTypeWriter *writer,  }  /** + * Initialize a write iterator, with the signature to be provided + * later. + * + * @param writer the writer to init + * @param byte_order the byte order to marshal into + * @param value_str the string to write values into + * @param value_pos where to insert values + * + */ +void +_dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, +                                      int             byte_order, +                                      DBusString     *value_str, +                                      int             value_pos) +{ +  _dbus_type_writer_init (writer, byte_order, +                          NULL, 0, value_str, value_pos); +} + +/** + * Adds type string to the writer, if it had none. + * + * @param writer the writer to init + * @param type_str type string to add + * @param type_pos type position + * + */ +void +_dbus_type_writer_add_types (DBusTypeWriter *writer, +                             DBusString     *type_str, +                             int             type_pos) +{ +  if (writer->type_str == NULL) /* keeps us from using this as setter */ +    { +      writer->type_str = type_str; +      writer->type_pos = type_pos; +    } +} + +/** + * Removes type string from the writer. + * + * @param writer the writer to remove from + */ +void +_dbus_type_writer_remove_types (DBusTypeWriter *writer) +{ +  writer->type_str = NULL; +  writer->type_pos = -1; +} + +/**   * Like _dbus_type_writer_init(), except the type string   * passed in should correspond to an existing signature that   * matches what you're going to write out. The writer will @@ -1438,19 +1589,21 @@ writer_recurse_init_and_check (DBusTypeWriter *writer,      }  #endif /* DBUS_DISABLE_CHECKS */ -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n", +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",                   writer,                   _dbus_type_to_string (writer->container_type),                   writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,                   writer->type_str ?                   _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : -                 "unknown"); -  _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d\n", +                 "unknown", +                 writer->enabled); +  _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",                   sub,                   _dbus_type_to_string (sub->container_type),                   sub->type_pos, sub->value_pos, -                 sub->type_pos_is_expectation); +                 sub->type_pos_is_expectation, +                 sub->enabled);  #endif  } @@ -1463,12 +1616,13 @@ write_or_verify_typecode (DBusTypeWriter *writer,     * or variant has type_pos pointing to the next place to insert a     * typecode.     */ -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n", +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",                   writer, writer->type_pos,                   writer->type_str ?                   _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : -                 "unknown"); +                 "unknown", +                 writer->enabled);  #endif    if (writer->type_str == NULL) @@ -1508,7 +1662,7 @@ write_or_verify_typecode (DBusTypeWriter *writer,        writer->type_pos += 1;      } -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE    _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",                   writer, writer->type_pos,                   _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0)); @@ -1558,7 +1712,8 @@ writer_recurse_array (DBusTypeWriter   *writer,                        const DBusString *contained_type,                        int               contained_type_start,                        int               contained_type_len, -                      DBusTypeWriter   *sub) +                      DBusTypeWriter   *sub, +                      dbus_bool_t       is_array_append)  {    dbus_uint32_t value = 0;    int alignment; @@ -1583,7 +1738,7 @@ writer_recurse_array (DBusTypeWriter   *writer,      }  #endif /* DBUS_DISABLE_CHECKS */ -  if (writer->enabled) +  if (writer->enabled && !is_array_append)      {        /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding         * before array values @@ -1633,12 +1788,19 @@ writer_recurse_array (DBusTypeWriter   *writer,    if (writer->enabled)      { -      /* Write the length */ +      /* Write (or jump over, if is_array_append) the length */        sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); -      if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32, -                                                      &value)) -        _dbus_assert_not_reached ("should not have failed to insert array len"); +      if (is_array_append) +        { +          sub->value_pos += 4; +        } +      else +        { +          if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32, +                                                          &value)) +            _dbus_assert_not_reached ("should not have failed to insert array len"); +        }        _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4); @@ -1651,32 +1813,48 @@ writer_recurse_array (DBusTypeWriter   *writer,        aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);        if (aligned != sub->value_pos)          { -          if (!_dbus_string_insert_bytes (sub->value_str, -                                          sub->value_pos, -                                          aligned - sub->value_pos, -                                          '\0')) -            _dbus_assert_not_reached ("should not have failed to insert alignment padding"); +          if (!is_array_append) +            { +              if (!_dbus_string_insert_bytes (sub->value_str, +                                              sub->value_pos, +                                              aligned - sub->value_pos, +                                              '\0')) +                _dbus_assert_not_reached ("should not have failed to insert alignment padding"); +            }            sub->value_pos = aligned;          } -#if RECURSIVE_MARSHAL_TRACE -      _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub, -                     sub->type_str ? -                     _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) : -                     "unknown", -                     sub->u.array.start_pos, sub->u.array.len_pos); -#endif +      sub->u.array.start_pos = sub->value_pos; + +      if (is_array_append) +        { +          dbus_uint32_t len; + +          len = _dbus_marshal_read_uint32 (sub->value_str, +                                           sub->u.array.len_pos, +                                           sub->byte_order, NULL); + +          sub->value_pos += len; +        }      }    else      {        /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */        sub->u.array.len_pos = -1; +      sub->u.array.start_pos = sub->value_pos;      } -  sub->u.array.start_pos = sub->value_pos; -  _dbus_assert (sub->u.array.start_pos == sub->value_pos);    _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos); +  _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos); + +#if RECURSIVE_MARSHAL_WRITE_TRACE +      _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub, +                     sub->type_str ? +                     _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) : +                     "unknown", +                     sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos); +#endif    return TRUE;  } @@ -1781,7 +1959,8 @@ _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,                                           const DBusString *contained_type,                                           int               contained_type_start,                                           int               contained_type_len, -                                         DBusTypeWriter   *sub) +                                         DBusTypeWriter   *sub, +                                         dbus_bool_t       is_array_append)  {    writer_recurse_init_and_check (writer, container_type, sub); @@ -1795,7 +1974,7 @@ _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,      case DBUS_TYPE_ARRAY:        return writer_recurse_array (writer,                                     contained_type, contained_type_start, contained_type_len, -                                   sub); +                                   sub, is_array_append);        break;      case DBUS_TYPE_VARIANT:        return writer_recurse_variant (writer, @@ -1827,7 +2006,41 @@ _dbus_type_writer_recurse (DBusTypeWriter   *writer,                                                    contained_type,                                                    contained_type_start,                                                    contained_type_len, -                                                  sub); +                                                  sub, +                                                  FALSE); +} + +/** + * Append to an existing array. Essentially, the writer will read an + * existing length at the write location; jump over that length; and + * write new fields. On unrecurse(), the existing length will be + * updated. + * + * @param writer the writer + * @param contained_type element type + * @param contained_type_start position of element type + * @param sub the subwriter to init + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_append_array (DBusTypeWriter   *writer, +                                const DBusString *contained_type, +                                int               contained_type_start, +                                DBusTypeWriter   *sub) +{ +  int contained_type_len; + +  if (contained_type) +    contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); +  else +    contained_type_len = 0; + +  return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY, +                                                  contained_type, +                                                  contained_type_start, +                                                  contained_type_len, +                                                  sub, +                                                  TRUE);  }  static int @@ -1845,7 +2058,7 @@ _dbus_type_writer_unrecurse (DBusTypeWriter *writer,    _dbus_assert (!writer->type_pos_is_expectation ||                  (writer->type_pos_is_expectation && sub->type_pos_is_expectation)); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE    _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",                   writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,                   _dbus_type_to_string (writer->container_type)); @@ -1872,12 +2085,12 @@ _dbus_type_writer_unrecurse (DBusTypeWriter *writer,                                      sub->u.array.len_pos,                                      len,                                      sub->byte_order); -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE            _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",                           len, sub->u.array.len_pos);  #endif          } -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE        else          {            _dbus_verbose ("    not filling in sub array len because we were disabled when we passed the len\n"); @@ -1940,7 +2153,7 @@ _dbus_type_writer_unrecurse (DBusTypeWriter *writer,    writer->value_pos = sub->value_pos; -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE    _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",                   writer, writer->type_pos, writer->value_pos,                   writer->type_str ? @@ -1959,7 +2172,7 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,    dbus_bool_t retval;    /* First ensure that our type realloc will succeed */ -  if (writer->type_str != NULL) +  if (!writer->type_pos_is_expectation && writer->type_str != NULL)      {        if (!_dbus_string_alloc_space (writer->type_str, 1))          return FALSE; @@ -1976,17 +2189,19 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,    retval = TRUE;   out: -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n", -                 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation); +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", +                 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, +                 writer->enabled);  #endif    return retval;  }  /** - * Writes an array of fixed-length basic values, i.e. those that - * are both _dbus_type_is_fixed() and _dbus_type_is_basic(). + * Writes a block of fixed-length basic values, i.e. those that are + * both _dbus_type_is_fixed() and _dbus_type_is_basic(). The block + * must be written inside an array.   *   * The value parameter should be the address of said array of values,   * so e.g. if it's an array of double, pass in "const double**" @@ -1998,7 +2213,7 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,   * @returns #FALSE if no memory   */  dbus_bool_t -_dbus_type_writer_write_fixed_array (DBusTypeWriter        *writer, +_dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,                                       int                    element_type,                                       const void            *value,                                       int                    n_elements) @@ -2006,13 +2221,19 @@ _dbus_type_writer_write_fixed_array (DBusTypeWriter        *writer,    _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);    _dbus_assert (_dbus_type_is_fixed (element_type));    _dbus_assert (writer->type_pos_is_expectation); +  _dbus_assert (n_elements >= 0); + +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n", +                 writer, writer->type_pos, writer->value_pos, n_elements); +#endif    if (!write_or_verify_typecode (writer, element_type))      _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");    if (writer->enabled)      { -      if (!_dbus_marshal_write_fixed_array (writer->value_str, +      if (!_dbus_marshal_write_fixed_multi (writer->value_str,                                              writer->value_pos,                                              element_type,                                              value, @@ -2022,9 +2243,9 @@ _dbus_type_writer_write_fixed_array (DBusTypeWriter        *writer,          return FALSE;      } -#if RECURSIVE_MARSHAL_TRACE -  _dbus_verbose ("  type writer %p fixed array type_pos = %d value_pos = %d\n", -                 writer, writer->type_pos, writer->value_pos); +#if RECURSIVE_MARSHAL_WRITE_TRACE +  _dbus_verbose ("  type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n", +                 writer, writer->type_pos, writer->value_pos, n_elements);  #endif    return TRUE; @@ -2040,9 +2261,9 @@ enable_if_after (DBusTypeWriter       *writer,        if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))          {            _dbus_type_writer_set_enabled (writer, TRUE); -#if RECURSIVE_MARSHAL_TRACE -          _dbus_verbose ("ENABLING writer %p because reader at value_pos %d is after reader at value_pos %d\n", -                         writer, reader->value_pos, start_after->value_pos); +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n", +                         writer, writer->value_pos, reader->value_pos, start_after->value_pos);  #endif          } @@ -2084,7 +2305,8 @@ writer_write_reader_helper (DBusTypeWriter       *writer,                              const DBusTypeReader *start_after,                              int                   start_after_new_pos,                              int                   start_after_new_len, -                            DBusList            **fixups) +                            DBusList            **fixups, +                            dbus_bool_t           inside_start_after)  {    int current_type; @@ -2101,6 +2323,20 @@ writer_write_reader_helper (DBusTypeWriter       *writer,            dbus_bool_t past_start_after;            int reader_array_len_pos;            int reader_array_start_pos; +          dbus_bool_t this_is_start_after; + +          /* type_pos is checked since e.g. in a struct the struct +           * and its first field have the same value_pos. +           * type_str will differ in reader/start_after for variants +           * where type_str is inside the value_str +           */ +          if (!inside_start_after && start_after && +              reader->value_pos == start_after->value_pos && +              reader->type_str == start_after->type_str && +              reader->type_pos == start_after->type_pos) +            this_is_start_after = TRUE; +          else +            this_is_start_after = FALSE;            _dbus_type_reader_recurse (reader, &subreader); @@ -2119,19 +2355,49 @@ writer_write_reader_helper (DBusTypeWriter       *writer,            _dbus_type_reader_get_signature (&subreader, &sig_str,                                             &sig_start, &sig_len); -          enable_if_after (writer, &subreader, start_after); +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n", +                         _dbus_type_to_string (current_type), +                         reader->value_pos, +                         subreader.value_pos, +                         writer->value_pos, +                         start_after ? start_after->value_pos : -1, +                         _dbus_string_get_length (writer->value_str), +                         inside_start_after, this_is_start_after); +#endif + +          if (!inside_start_after && !this_is_start_after) +            enable_if_after (writer, &subreader, start_after);            enabled_at_recurse = writer->enabled;            if (!_dbus_type_writer_recurse_contained_len (writer, current_type,                                                          sig_str, sig_start, sig_len, -                                                        &subwriter)) +                                                        &subwriter, FALSE))              goto oom; +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("recursed into subwriter at %d write target len %d\n", +                         subwriter.value_pos, +                         _dbus_string_get_length (subwriter.value_str)); +#endif +            if (!writer_write_reader_helper (&subwriter, &subreader, start_after,                                             start_after_new_pos, start_after_new_len, -                                           fixups)) +                                           fixups, +                                           inside_start_after || +                                           this_is_start_after))              goto oom; -          enable_if_after (writer, &subreader, start_after); +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d  write target len %d\n", +                         _dbus_type_to_string (current_type), +                         subreader.value_pos, +                         writer->value_pos, +                         subwriter.value_pos, +                         _dbus_string_get_length (writer->value_str)); +#endif + +          if (!inside_start_after && !this_is_start_after) +            enable_if_after (writer, &subreader, start_after);            past_start_after = writer->enabled;            if (!_dbus_type_writer_unrecurse (writer, &subwriter))              goto oom; @@ -2151,8 +2417,9 @@ writer_write_reader_helper (DBusTypeWriter       *writer,                int bytes_before_start_after;                int old_len; -              /* this is moderately unkosher since we already unrecursed, -               * but it works as long as unrecurse doesn't break us on purpose +              /* this subwriter access is moderately unkosher since we +               * already unrecursed, but it works as long as unrecurse +               * doesn't break us on purpose                 */                bytes_written_after_start_after = writer_get_array_len (&subwriter); @@ -2172,7 +2439,7 @@ writer_write_reader_helper (DBusTypeWriter       *writer,                if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))                  goto oom; -#if RECURSIVE_MARSHAL_TRACE +#if RECURSIVE_MARSHAL_WRITE_TRACE                _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n",                               fixup.len_pos_in_reader,                               fixup.new_len, @@ -2190,11 +2457,31 @@ writer_write_reader_helper (DBusTypeWriter       *writer,            _dbus_assert (_dbus_type_is_basic (current_type)); +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("Reading basic value %s at %d\n", +                         _dbus_type_to_string (current_type), +                         reader->value_pos); +#endif +            _dbus_type_reader_read_basic (reader, &val); -          enable_if_after (writer, reader, start_after); +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n", +                         _dbus_type_to_string (current_type), +                         writer->value_pos, +                         _dbus_string_get_length (writer->value_str), +                         inside_start_after); +#endif +          if (!inside_start_after) +            enable_if_after (writer, reader, start_after);            if (!_dbus_type_writer_write_basic (writer, current_type, &val))              goto oom; +#if RECURSIVE_MARSHAL_WRITE_TRACE +          _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n", +                         _dbus_type_to_string (current_type), +                         writer->value_pos, +                         _dbus_string_get_length (writer->value_str)); +#endif          }        _dbus_type_reader_next (reader); @@ -2265,7 +2552,7 @@ _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,    if (!writer_write_reader_helper (writer, reader, start_after,                                     start_after_new_pos,                                     start_after_new_len, -                                   fixups)) +                                   fixups, FALSE))      goto oom;    _dbus_type_writer_set_enabled (writer, orig_enabled); @@ -2572,6 +2859,15 @@ struct TestTypeNodeClass                                     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 @@ -2595,6 +2891,15 @@ 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, @@ -2721,7 +3026,9 @@ static const TestTypeNodeClass int32_class = {    int32_write_value,    int32_read_value,    int32_set_value, -  NULL +  NULL, +  int32_write_multi, +  int32_read_multi  };  static const TestTypeNodeClass uint32_class = { @@ -2733,7 +3040,9 @@ static const TestTypeNodeClass uint32_class = {    int32_write_value, /* recycle from int32 */    int32_read_value,  /* recycle from int32 */    int32_set_value,   /* recycle from int32 */ -  NULL +  NULL, +  int32_write_multi, /* recycle from int32 */ +  int32_read_multi   /* recycle from int32 */  };  static const TestTypeNodeClass int64_class = { @@ -2745,7 +3054,9 @@ static const TestTypeNodeClass int64_class = {    int64_write_value,    int64_read_value,    int64_set_value, -  NULL +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */  };  static const TestTypeNodeClass uint64_class = { @@ -2757,7 +3068,9 @@ static const TestTypeNodeClass uint64_class = {    int64_write_value, /* recycle from int64 */    int64_read_value,  /* recycle from int64 */    int64_set_value,   /* recycle from int64 */ -  NULL +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */  };  static const TestTypeNodeClass string_0_class = { @@ -2769,6 +3082,8 @@ static const TestTypeNodeClass string_0_class = {    string_write_value,    string_read_value,    string_set_value, +  NULL, +  NULL,    NULL  }; @@ -2781,6 +3096,8 @@ static const TestTypeNodeClass string_1_class = {    string_write_value,    string_read_value,    string_set_value, +  NULL, +  NULL,    NULL  }; @@ -2794,6 +3111,8 @@ static const TestTypeNodeClass string_3_class = {    string_write_value,    string_read_value,    string_set_value, +  NULL, +  NULL,    NULL  }; @@ -2807,6 +3126,8 @@ static const TestTypeNodeClass string_8_class = {    string_write_value,    string_read_value,    string_set_value, +  NULL, +  NULL,    NULL  }; @@ -2819,7 +3140,9 @@ static const TestTypeNodeClass bool_class = {    bool_write_value,    bool_read_value,    bool_set_value, -  NULL +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */  };  static const TestTypeNodeClass byte_class = { @@ -2831,7 +3154,9 @@ static const TestTypeNodeClass byte_class = {    byte_write_value,    byte_read_value,    byte_set_value, -  NULL +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */  };  static const TestTypeNodeClass double_class = { @@ -2843,7 +3168,9 @@ static const TestTypeNodeClass double_class = {    double_write_value,    double_read_value,    double_set_value, -  NULL +  NULL, +  NULL, /* FIXME */ +  NULL  /* FIXME */  };  static const TestTypeNodeClass object_path_class = { @@ -2855,6 +3182,8 @@ static const TestTypeNodeClass object_path_class = {    object_path_write_value,    object_path_read_value,    object_path_set_value, +  NULL, +  NULL,    NULL  }; @@ -2867,6 +3196,8 @@ static const TestTypeNodeClass signature_class = {    signature_write_value,    signature_read_value,    signature_set_value, +  NULL, +  NULL,    NULL  }; @@ -2879,7 +3210,9 @@ static const TestTypeNodeClass struct_1_class = {    struct_write_value,    struct_read_value,    struct_set_value, -  struct_build_signature +  struct_build_signature, +  NULL, +  NULL  };  static const TestTypeNodeClass struct_2_class = { @@ -2891,9 +3224,13 @@ static const TestTypeNodeClass struct_2_class = {    struct_write_value,    struct_read_value,    struct_set_value, -  struct_build_signature +  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), @@ -2903,7 +3240,9 @@ static const TestTypeNodeClass array_0_class = {    array_write_value,    array_read_value,    array_set_value, -  array_build_signature +  array_build_signature, +  NULL, +  NULL  };  static const TestTypeNodeClass array_1_class = { @@ -2915,7 +3254,9 @@ static const TestTypeNodeClass array_1_class = {    array_write_value,    array_read_value,    array_set_value, -  array_build_signature +  array_build_signature, +  NULL, +  NULL  };  static const TestTypeNodeClass array_2_class = { @@ -2927,7 +3268,9 @@ static const TestTypeNodeClass array_2_class = {    array_write_value,    array_read_value,    array_set_value, -  array_build_signature +  array_build_signature, +  NULL, +  NULL  };  static const TestTypeNodeClass array_9_class = { @@ -2939,7 +3282,9 @@ static const TestTypeNodeClass array_9_class = {    array_write_value,    array_read_value,    array_set_value, -  array_build_signature +  array_build_signature, +  NULL, +  NULL  };  static const TestTypeNodeClass variant_class = { @@ -2951,6 +3296,8 @@ static const TestTypeNodeClass variant_class = {    variant_write_value,    variant_read_value,    variant_set_value, +  NULL, +  NULL,    NULL  }; @@ -3100,6 +3447,40 @@ node_append_child (TestTypeNode *node,    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; @@ -3305,6 +3686,102 @@ run_test_set_values (NodeIterationData *nid)  }  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); +              _dbus_assert (!_dbus_type_reader_array_is_empty (&reader)); + +              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) +    { +      if (t == DBUS_TYPE_ARRAY) +        _dbus_assert (_dbus_type_reader_array_is_empty (&reader)); + +      _dbus_type_reader_next (&reader); +    } + +  retval = TRUE; + + out: +  return retval; +} + +static dbus_bool_t  run_test_nodes_iteration (void *data)  {    NodeIterationData *nid = data; @@ -3376,6 +3853,9 @@ run_test_nodes_iteration (void *data)        if (!run_test_set_values (nid))          goto out; +      if (!run_test_delete_values (nid)) +        goto out; +        if (!run_test_copy (nid))          goto out; @@ -3625,6 +4105,20 @@ make_and_run_test_nodes (void)        }    } +  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]; @@ -3668,10 +4162,19 @@ make_and_run_test_nodes (void)        make_and_run_values_inside_container (container_klass, 1);      } -  n_iterations_completed_this_test = 0; -  n_iterations_expected_this_test = N_CONTAINERS * N_VALUES; -  _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n", -                 n_iterations_completed_this_test); +  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]; @@ -3865,8 +4368,6 @@ make_and_run_test_nodes (void)             TEST_OOM_HANDLING ? "was" : "was not");  } -dbus_bool_t _dbus_marshal_recursive_test (void); -  dbus_bool_t  _dbus_marshal_recursive_test (void)  { @@ -3875,20 +4376,6 @@ _dbus_marshal_recursive_test (void)    return TRUE;  } -#if 1 -dbus_bool_t _dbus_marshal_test (void); -int -main (int argc, char **argv) -{ -  _dbus_marshal_test (); - -  _dbus_marshal_recursive_test (); - -  return 0; -} -#endif /* main() */ - -  /*   *   * @@ -3897,6 +4384,7 @@ main (int argc, char **argv)   *   *   */ +#define MAX_MULTI_COUNT 5  #define SAMPLE_INT32           12345678 @@ -3986,6 +4474,55 @@ int32_set_value (TestTypeNode   *node,                                        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) @@ -4162,6 +4699,15 @@ string_set_value (TestTypeNode   *node,    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); @@ -4686,6 +5232,8 @@ array_write_value (TestTypeNode   *node,    DBusString element_signature;    int i;    int n_copies; +  int element_type; +  TestTypeNode *child;    n_copies = node->klass->subclass_detail; @@ -4696,33 +5244,47 @@ array_write_value (TestTypeNode   *node,    if (!_dbus_string_init (&element_signature))      return FALSE; -  if (!node_build_signature (_dbus_list_get_first (&container->children), +  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; -  i = 0; -  while (i < n_copies) +  if (arrays_write_fixed_in_blocks && +      _dbus_type_is_fixed (element_type) && +      child->klass->write_multi)      { -      DBusList *link; - -      link = _dbus_list_get_first_link (&container->children); -      while (link != NULL) +      if (!node_write_multi (child, block, &sub, seed, n_copies)) +        goto oom; +    } +  else +    { +      i = 0; +      while (i < n_copies)          { -          TestTypeNode *child = link->data; -          DBusList *next = _dbus_list_get_next_link (&container->children, link); +          DBusList *link; -          if (!node_write_value (child, block, &sub, seed + i)) -            goto oom; +          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); -          link = next; -        } +              if (!node_write_value (child, block, &sub, seed + i)) +                goto oom; -      ++i; +              link = next; +            } + +          ++i; +        }      }    if (!_dbus_type_writer_unrecurse (writer, &sub)) @@ -4747,48 +5309,64 @@ array_read_or_set_value (TestTypeNode   *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_assert (!_dbus_type_reader_array_is_empty (reader));        _dbus_type_reader_recurse (reader, &sub); -      i = 0; -      while (i < n_copies) +      if (realign_root == NULL && arrays_write_fixed_in_blocks && +          _dbus_type_is_fixed (_dbus_type_reader_get_array_type (reader)) && +          child->klass->read_multi)          { -          DBusList *link; - -          link = _dbus_list_get_first_link (&container->children); -          while (link != NULL) +          if (!node_read_multi (child, &sub, seed, n_copies)) +            return FALSE; +        } +      else +        { +          i = 0; +          while (i < n_copies)              { -              TestTypeNode *child = link->data; -              DBusList *next = _dbus_list_get_next_link (&container->children, link); +              DBusList *link; -              if (realign_root == NULL) -                { -                  if (!node_read_value (child, &sub, seed + i)) -                    return FALSE; -                } -              else +              link = _dbus_list_get_first_link (&container->children); +              while (link != NULL)                  { -                  if (!node_set_value (child, &sub, realign_root, seed + i)) -                    return FALSE; +                  TestTypeNode *child = link->data; +                  DBusList *next = _dbus_list_get_next_link (&container->children, link); + +                  _dbus_assert (child->klass->typecode == +                                _dbus_type_reader_get_array_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;                  } -              if (i == (n_copies - 1) && next == NULL) -                NEXT_EXPECTING_FALSE (&sub); -              else -                NEXT_EXPECTING_TRUE (&sub); - -              link = next; +              ++i;              } - -          ++i;          }      }    else diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h index 765ee56b..203e2f8c 100644 --- a/dbus/dbus-marshal-recursive.h +++ b/dbus/dbus-marshal-recursive.h @@ -1,7 +1,7 @@  /* -*- mode: C; c-file-style: "gnu" -*- */  /* dbus-marshal-recursive.h  Marshalling routines for recursive types   * - * Copyright (C) 2004 Red Hat, Inc. + * Copyright (C) 2004, 2005 Red Hat, Inc.   *   * Licensed under the Academic Free License version 2.1   * @@ -148,12 +148,16 @@ void        _dbus_type_reader_init_types_only_from_mark (DBusTypeReader        *  void        _dbus_type_reader_save_mark                 (const DBusTypeReader  *reader,                                                           DBusTypeMark          *mark);  int         _dbus_type_reader_get_current_type          (const DBusTypeReader  *reader); +int         _dbus_type_reader_get_array_type            (const DBusTypeReader  *reader); +int         _dbus_type_reader_get_value_pos             (const DBusTypeReader  *reader);  dbus_bool_t _dbus_type_reader_array_is_empty            (const DBusTypeReader  *reader);  void        _dbus_type_reader_read_basic                (const DBusTypeReader  *reader,                                                           void                  *value); -void        _dbus_type_reader_read_fixed_array          (const DBusTypeReader  *reader, +void        _dbus_type_reader_read_fixed_multi          (const DBusTypeReader  *reader,                                                           void                  *value,                                                           int                   *n_elements); +void        _dbus_type_reader_read_raw                  (const DBusTypeReader  *reader, +                                                         const unsigned char  **value_location);  void        _dbus_type_reader_recurse                   (DBusTypeReader        *reader,                                                           DBusTypeReader        *subreader);  dbus_bool_t _dbus_type_reader_next                      (DBusTypeReader        *reader); @@ -176,6 +180,14 @@ void        _dbus_type_writer_init                 (DBusTypeWriter        *write                                                      int                    type_pos,                                                      DBusString            *value_str,                                                      int                    value_pos); +void        _dbus_type_writer_init_types_delayed   (DBusTypeWriter        *writer, +                                                    int                    byte_order, +                                                    DBusString            *value_str, +                                                    int                    value_pos); +void        _dbus_type_writer_add_types            (DBusTypeWriter        *writer, +                                                    DBusString            *type_str, +                                                    int                    type_pos); +void        _dbus_type_writer_remove_types         (DBusTypeWriter        *writer);  void        _dbus_type_writer_init_values_only     (DBusTypeWriter        *writer,                                                      int                    byte_order,                                                      const DBusString      *type_str, @@ -185,7 +197,7 @@ void        _dbus_type_writer_init_values_only     (DBusTypeWriter        *write  dbus_bool_t _dbus_type_writer_write_basic          (DBusTypeWriter        *writer,                                                      int                    type,                                                      const void            *value); -dbus_bool_t _dbus_type_writer_write_fixed_array    (DBusTypeWriter        *writer, +dbus_bool_t _dbus_type_writer_write_fixed_multi    (DBusTypeWriter        *writer,                                                      int                    element_type,                                                      const void            *value,                                                      int                    n_elements); @@ -196,6 +208,10 @@ dbus_bool_t _dbus_type_writer_recurse              (DBusTypeWriter        *write                                                      DBusTypeWriter        *sub);  dbus_bool_t _dbus_type_writer_unrecurse            (DBusTypeWriter        *writer,                                                      DBusTypeWriter        *sub); +dbus_bool_t _dbus_type_writer_append_array         (DBusTypeWriter        *writer, +                                                    const DBusString      *contained_type, +                                                    int                    contained_type_start, +                                                    DBusTypeWriter        *sub);  dbus_bool_t _dbus_type_writer_write_reader         (DBusTypeWriter        *writer,                                                      DBusTypeReader        *reader);  dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter        *writer, @@ -208,5 +224,4 @@ void        _dbus_type_writer_set_enabled          (DBusTypeWriter        *write                                                      dbus_bool_t            enabled); -  #endif /* DBUS_MARSHAL_RECURSIVE_H */ diff --git a/dbus/dbus-marshal-validate.c b/dbus/dbus-marshal-validate.c index 97041189..cf409758 100644 --- a/dbus/dbus-marshal-validate.c +++ b/dbus/dbus-marshal-validate.c @@ -23,6 +23,7 @@  #include "dbus-internals.h"  #include "dbus-marshal-validate.h" +#include "dbus-marshal-recursive.h"  /**   * @addtogroup DBusMarshal @@ -30,15 +31,1279 @@   * @{   */ +/** + * Verifies that the range of type_str from type_pos to type_end is a + * valid signature.  If this function returns #TRUE, it will be safe + * to iterate over the signature with a types-only #DBusTypeReader. + * The range passed in should NOT include the terminating + * nul/DBUS_TYPE_INVALID. + * + * @param type_str the string + * @param type_pos where the typecodes start + * @param len length of typecodes + * @returns #DBUS_VALID if valid, reason why invalid otherwise + */ +DBusValidity +_dbus_validate_signature_with_reason (const DBusString *type_str, +                                      int               type_pos, +                                      int               len) +{ +  const unsigned char *p; +  const unsigned char *end; +  int last; +  int struct_depth; +  int array_depth; + +  _dbus_assert (type_str != NULL); +  _dbus_assert (type_pos < _DBUS_INT_MAX - len); +  _dbus_assert (len >= 0); +  _dbus_assert (type_pos >= 0); + +  if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH) +    return DBUS_INVALID_SIGNATURE_TOO_LONG; + +  p = _dbus_string_get_const_data_len (type_str, type_pos, 0); +  end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0); +  struct_depth = 0; +  array_depth = 0; +  last = DBUS_TYPE_INVALID; + +  while (p != end) +    { +      switch (*p) +        { +        case DBUS_TYPE_BYTE: +        case DBUS_TYPE_BOOLEAN: +        case DBUS_TYPE_INT32: +        case DBUS_TYPE_UINT32: +        case DBUS_TYPE_INT64: +        case DBUS_TYPE_UINT64: +        case DBUS_TYPE_DOUBLE: +        case DBUS_TYPE_STRING: +        case DBUS_TYPE_OBJECT_PATH: +        case DBUS_TYPE_SIGNATURE: +        case DBUS_TYPE_VARIANT: +          break; + +        case DBUS_TYPE_ARRAY: +          array_depth += 1; +          if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) +            return DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; +          break; + +        case DBUS_STRUCT_BEGIN_CHAR: +          struct_depth += 1; + +          if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) +            return DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; +          break; + +        case DBUS_STRUCT_END_CHAR: +          if (struct_depth == 0) +            return DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; + +          if (last == DBUS_STRUCT_BEGIN_CHAR) +            return DBUS_INVALID_STRUCT_HAS_NO_FIELDS; + +          struct_depth -= 1; +          break; + +        case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */ +        default: +          return DBUS_INVALID_UNKNOWN_TYPECODE; +        } + +      if (*p != DBUS_TYPE_ARRAY) +        array_depth = 0; + +      last = *p; +      ++p; +    } + +  if (array_depth > 0) +    return DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; + +  if (struct_depth > 0) +    return DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; + +  return DBUS_VALID; +} + +static DBusValidity +validate_body_helper (DBusTypeReader       *reader, +                      int                   byte_order, +                      dbus_bool_t           walk_reader_to_end, +                      const unsigned char  *p, +                      const unsigned char  *end, +                      const unsigned char **new_p) +{ +  int current_type; + +  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) +    { +      const unsigned char *a; +      int alignment; + +      _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n", +                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, +                     (int) (end - p)); + +      /* Guarantee that p has one byte to look at */ +      if (p == end) +        return DBUS_INVALID_NOT_ENOUGH_DATA; + +      switch (current_type) +        { +        case DBUS_TYPE_BYTE: +          ++p; +          break; + +        case DBUS_TYPE_BOOLEAN: +          if (!(*p == 0 || *p == 1)) +            return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE; +          ++p; +          break; + +        case DBUS_TYPE_INT32: +        case DBUS_TYPE_UINT32: +        case DBUS_TYPE_INT64: +        case DBUS_TYPE_UINT64: +        case DBUS_TYPE_DOUBLE: +          alignment = _dbus_type_get_alignment (current_type); +          a = _DBUS_ALIGN_ADDRESS (p, alignment); +          if (a >= end) +            return DBUS_INVALID_NOT_ENOUGH_DATA; +          while (p != a) +            { +              if (*p != '\0') +                return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; +              ++p; +            } +          p += alignment; +          break; + +        case DBUS_TYPE_ARRAY: +        case DBUS_TYPE_STRING: +        case DBUS_TYPE_OBJECT_PATH: +          { +            dbus_uint32_t claimed_len; + +            a = _DBUS_ALIGN_ADDRESS (p, 4); +            if (a + 4 >= end) +              return DBUS_INVALID_NOT_ENOUGH_DATA; +            while (p != a) +              { +                if (*p != '\0') +                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; +                ++p; +              } + +            claimed_len = _dbus_unpack_uint32 (byte_order, p); +            p += 4; + +            if (current_type == DBUS_TYPE_ARRAY) +              { +                int array_elem_type = _dbus_type_reader_get_array_type (reader); +                alignment = _dbus_type_get_alignment (array_elem_type); +                p = _DBUS_ALIGN_ADDRESS (p, alignment); +              } + +            if (claimed_len > (unsigned long) (end - p)) +              return DBUS_INVALID_STRING_LENGTH_OUT_OF_BOUNDS; + +            if (current_type == DBUS_TYPE_OBJECT_PATH) +              { +                DBusString str; +                _dbus_string_init_const_len (&str, p, claimed_len); +                if (!_dbus_validate_path (&str, 0, +                                          _dbus_string_get_length (&str))) +                  return DBUS_INVALID_BAD_PATH; + +                p += claimed_len; +              } +            else if (current_type == DBUS_TYPE_STRING) +              { +                DBusString str; +                _dbus_string_init_const_len (&str, p, claimed_len); +                if (!_dbus_string_validate_utf8 (&str, 0, +                                                 _dbus_string_get_length (&str))) +                  return DBUS_INVALID_BAD_UTF8_IN_STRING; + +                p += claimed_len; +              } +            else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0) +              { +                DBusTypeReader sub; +                DBusValidity validity; +                const unsigned char *array_end; + +                /* Remember that the reader is types only, so we can't +                 * use it to iterate over elements. It stays the same +                 * for all elements. +                 */ +                _dbus_type_reader_recurse (reader, &sub); + +                array_end = p + claimed_len; + +                while (p < array_end) +                  { +                    validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p); +                    if (validity != DBUS_VALID) +                      return validity; +                  } + +                if (p != array_end) +                  return DBUS_INVALID_ARRAY_LENGTH_INCORRECT; +              } + +            /* check nul termination */ +            if (current_type != DBUS_TYPE_ARRAY) +              { +                if (p == end) +                  return DBUS_INVALID_NOT_ENOUGH_DATA; + +                if (*p != '\0') +                  return DBUS_INVALID_STRING_MISSING_NUL; +                ++p; +              } +          } +          break; + +        case DBUS_TYPE_SIGNATURE: +          { +            dbus_uint32_t claimed_len; +            DBusString str; + +            claimed_len = *p; +            ++p; + +            /* 1 is for nul termination */ +            if (claimed_len + 1 > (unsigned long) (end - p)) +              return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS; + +            _dbus_string_init_const_len (&str, p, claimed_len); +            if (!_dbus_validate_signature (&str, 0, +                                           _dbus_string_get_length (&str))) +              return DBUS_INVALID_BAD_SIGNATURE; + +            p += claimed_len; + +            _dbus_assert (p < end); +            if (*p != DBUS_TYPE_INVALID) +              return DBUS_INVALID_SIGNATURE_MISSING_NUL; + +            ++p; + +            _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len); +          } +          break; + +        case DBUS_TYPE_VARIANT: +          { +            /* 1 byte sig len, sig typecodes, align to 8-boundary, values. */ +            /* In addition to normal signature validation, we need to be sure +             * the signature contains only a single (possibly container) type. +             */ +            dbus_uint32_t claimed_len; +            DBusString sig; +            DBusTypeReader sub; +            DBusValidity validity; + +            claimed_len = *p; +            ++p; + +            /* + 1 for nul */ +            if (claimed_len + 1 > (unsigned long) (end - p)) +              return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS; + +            _dbus_string_init_const_len (&sig, p, claimed_len); +            if (!_dbus_validate_signature (&sig, 0, +                                           _dbus_string_get_length (&sig))) +              return DBUS_INVALID_VARIANT_SIGNATURE_BAD; + +            p += claimed_len; + +            if (*p != DBUS_TYPE_INVALID) +              return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL; +            ++p; + +            a = _DBUS_ALIGN_ADDRESS (p, 8); +            if (a > end) +              return DBUS_INVALID_NOT_ENOUGH_DATA; +            while (p != a) +              { +                if (*p != '\0') +                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; +                ++p; +              } + +            _dbus_type_reader_init_types_only (&sub, &sig, 0); + +            if (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID) +              return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY; + +            validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p); +            if (validity != DBUS_VALID) +              return validity; + +            if (_dbus_type_reader_next (&sub)) +              return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES; + +            _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID); +          } +          break; + +        case DBUS_TYPE_STRUCT: +          { +            DBusTypeReader sub; +            DBusValidity validity; + +            a = _DBUS_ALIGN_ADDRESS (p, 8); +            if (a > end) +              return DBUS_INVALID_NOT_ENOUGH_DATA; +            while (p != a) +              { +                if (*p != '\0') +                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; +                ++p; +              } + +            _dbus_type_reader_recurse (reader, &sub); + +            validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p); +            if (validity != DBUS_VALID) +              return validity; +          } +          break; + +        default: +          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); +          break; +        } + +      _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n", +                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, +                     (int) (end - p)); + +      if (p > end) +        { +          _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n", +                         p, end, (int) (end - p)); +          return DBUS_INVALID_NOT_ENOUGH_DATA; +        } + +      if (walk_reader_to_end) +        _dbus_type_reader_next (reader); +      else +        break; +    } + +  if (new_p) +    *new_p = p; + +  return DBUS_VALID; +} + +/** + * Verifies that the range of value_str from value_pos to value_end is + * a legitimate value of type expected_signature.  If this function + * returns #TRUE, it will be safe to iterate over the values with + * #DBusTypeReader. The signature is assumed to be already valid. + * + * If bytes_remaining is not #NULL, then leftover bytes will be stored + * there and #DBUS_VALID returned. If it is #NULL, then + * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left + * over. + * + * @param expected_signature the expected types in the value_str + * @param expected_signature_start where in expected_signature is the signature + * @param byte_order the byte order + * @param bytes_remaining place to store leftover bytes + * @param value_pos where the values start + * @param len length of values after value_pos + * @returns #DBUS_VALID if valid, reason why invalid otherwise + */ +DBusValidity +_dbus_validate_body_with_reason (const DBusString *expected_signature, +                                 int               expected_signature_start, +                                 int               byte_order, +                                 int              *bytes_remaining, +                                 const DBusString *value_str, +                                 int               value_pos, +                                 int               len) +{ +  DBusTypeReader reader; +  const unsigned char *p; +  const unsigned char *end; +  DBusValidity validity; + +  _dbus_assert (len >= 0); +  _dbus_assert (value_pos >= 0); +  _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len); + +  _dbus_verbose ("validating body from pos %d len %d sig '%s'\n", +                 value_pos, len, _dbus_string_get_const_data_len (expected_signature, +                                                                  expected_signature_start, +                                                                  0)); + +  _dbus_type_reader_init_types_only (&reader, +                                     expected_signature, expected_signature_start); + +  p = _dbus_string_get_const_data_len (value_str, value_pos, len); +  end = p + len; + +  validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p); +  if (validity != DBUS_VALID) +    return validity; + +  if (p < end) +    { +      if (bytes_remaining) +        *bytes_remaining = end - p; +      else +        return DBUS_INVALID_TOO_MUCH_DATA; +    } + +  return DBUS_VALID; +} + +/** + * Checks that the given range of the string is a valid object path + * name in the D-BUS protocol. Part of the validation ensures that + * the object path contains only ASCII. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @todo change spec to disallow more things, such as spaces in the + * path name + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_path (const DBusString  *str, +                     int                start, +                     int                len) +{ +  const unsigned char *s; +  const unsigned char *end; +  const unsigned char *last_slash; + +  _dbus_assert (start >= 0); +  _dbus_assert (len >= 0); +  _dbus_assert (start <= _dbus_string_get_length (str)); + +  if (len > _dbus_string_get_length (str) - start) +    return FALSE; + +  if (len == 0) +    return FALSE; + +  s = _dbus_string_get_const_data (str) + start; +  end = s + len; + +  if (*s != '/') +    return FALSE; +  last_slash = s; +  ++s; + +  while (s != end) +    { +      if (*s == '/') +        { +          if ((s - last_slash) < 2) +            return FALSE; /* no empty path components allowed */ + +          last_slash = s; +        } +      else +        { +          if (_DBUS_UNLIKELY (!_DBUS_ISASCII (*s))) +            return FALSE; +        } + +      ++s; +    } + +  if ((end - last_slash) < 2 && +      len > 1) +    return FALSE; /* trailing slash not allowed unless the string is "/" */ + +  return TRUE; +} + +/** + * Determine wether the given charater is valid as the first charater + * in a name. + */ +#define VALID_INITIAL_NAME_CHARACTER(c)         \ +  ( ((c) >= 'A' && (c) <= 'Z') ||               \ +    ((c) >= 'a' && (c) <= 'z') ||               \ +    ((c) == '_') ) + +/** + * Determine wether the given charater is valid as a second or later + * character in a name + */ +#define VALID_NAME_CHARACTER(c)                 \ +  ( ((c) >= '0' && (c) <= '9') ||               \ +    ((c) >= 'A' && (c) <= 'Z') ||               \ +    ((c) >= 'a' && (c) <= 'z') ||               \ +    ((c) == '_') ) + +/** + * Checks that the given range of the string is a valid interface name + * in the D-BUS protocol. This includes a length restriction and an + * ASCII subset, see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_interface (const DBusString  *str, +                          int                start, +                          int                len) +{ +  const unsigned char *s; +  const unsigned char *end; +  const unsigned char *iface; +  const unsigned char *last_dot; + +  _dbus_assert (start >= 0); +  _dbus_assert (len >= 0); +  _dbus_assert (start <= _dbus_string_get_length (str)); + +  if (len > _dbus_string_get_length (str) - start) +    return FALSE; + +  if (len > DBUS_MAXIMUM_NAME_LENGTH) +    return FALSE; + +  if (len == 0) +    return FALSE; + +  last_dot = NULL; +  iface = _dbus_string_get_const_data (str) + start; +  end = iface + len; +  s = iface; + +  /* check special cases of first char so it doesn't have to be done +   * in the loop. Note we know len > 0 +   */ +  if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ +    return FALSE; +  else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) +    return FALSE; +  else +    ++s; + +  while (s != end) +    { +      if (*s == '.') +        { +          if (_DBUS_UNLIKELY ((s + 1) == end)) +            return FALSE; +          else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1)))) +            return FALSE; +          last_dot = s; +          ++s; /* we just validated the next char, so skip two */ +        } +      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) +        { +          return FALSE; +        } + +      ++s; +    } + +  if (_DBUS_UNLIKELY (last_dot == NULL)) +    return FALSE; + +  return TRUE; +} + +/** + * Checks that the given range of the string is a valid member name + * in the D-BUS protocol. This includes a length restriction, etc., + * see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_member (const DBusString  *str, +                       int                start, +                       int                len) +{ +  const unsigned char *s; +  const unsigned char *end; +  const unsigned char *member; + +  _dbus_assert (start >= 0); +  _dbus_assert (len >= 0); +  _dbus_assert (start <= _dbus_string_get_length (str)); + +  if (len > _dbus_string_get_length (str) - start) +    return FALSE; + +  if (len > DBUS_MAXIMUM_NAME_LENGTH) +    return FALSE; + +  if (len == 0) +    return FALSE; + +  member = _dbus_string_get_const_data (str) + start; +  end = member + len; +  s = member; + +  /* check special cases of first char so it doesn't have to be done +   * in the loop. Note we know len > 0 +   */ + +  if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) +    return FALSE; +  else +    ++s; + +  while (s != end) +    { +      if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) +        { +          return FALSE; +        } + +      ++s; +    } + +  return TRUE; +} + +/** + * Checks that the given range of the string is a valid error name + * in the D-BUS protocol. This includes a length restriction, etc., + * see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_error_name (const DBusString  *str, +                           int                start, +                           int                len) +{ +  /* Same restrictions as interface name at the moment */ +  return _dbus_validate_interface (str, start, len); +} + +/* This assumes the first char exists and is ':' */ +static dbus_bool_t +_dbus_validate_base_service (const DBusString  *str, +                             int                start, +                             int                len) +{ +  const unsigned char *s; +  const unsigned char *end; +  const unsigned char *service; + +  _dbus_assert (start >= 0); +  _dbus_assert (len >= 0); +  _dbus_assert (start <= _dbus_string_get_length (str)); + +  if (len > _dbus_string_get_length (str) - start) +    return FALSE; + +  if (len > DBUS_MAXIMUM_NAME_LENGTH) +    return FALSE; + +  _dbus_assert (len > 0); + +  service = _dbus_string_get_const_data (str) + start; +  end = service + len; +  _dbus_assert (*service == ':'); +  s = service + 1; + +  while (s != end) +    { +      if (*s == '.') +        { +          if (_DBUS_UNLIKELY ((s + 1) == end)) +            return FALSE; +          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1)))) +            return FALSE; +          ++s; /* we just validated the next char, so skip two */ +        } +      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) +        { +          return FALSE; +        } + +      ++s; +    } + +  return TRUE; +} + +/** + * Checks that the given range of the string is a valid service name + * in the D-BUS protocol. This includes a length restriction, etc., + * see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_service (const DBusString  *str, +                        int                start, +                        int                len) +{ +  if (_DBUS_UNLIKELY (len == 0)) +    return FALSE; +  if (_dbus_string_get_byte (str, start) == ':') +    return _dbus_validate_base_service (str, start, len); +  else +    return _dbus_validate_interface (str, start, len); +} + +/** + * Checks that the given range of the string is a valid message type + * signature in the D-BUS protocol. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid signature + */ +dbus_bool_t +_dbus_validate_signature (const DBusString  *str, +                          int                start, +                          int                len) +{ +  _dbus_assert (start >= 0); +  _dbus_assert (start <= _dbus_string_get_length (str)); +  _dbus_assert (len >= 0); + +  if (len > _dbus_string_get_length (str) - start) +    return FALSE; + +  return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID; +} + +/* If the compiler hates these semicolons, add "extern int + * allow_parens" at the end in the the macro perhaps + */ +DEFINE_DBUS_NAME_CHECK(path); +DEFINE_DBUS_NAME_CHECK(interface); +DEFINE_DBUS_NAME_CHECK(member); +DEFINE_DBUS_NAME_CHECK(error_name); +DEFINE_DBUS_NAME_CHECK(service); +DEFINE_DBUS_NAME_CHECK(signature); +  /** @} */  #ifdef DBUS_BUILD_TESTS  #include "dbus-test.h"  #include <stdio.h> +typedef struct +{ +  const char *data; +  DBusValidity expected; +} ValidityTest; + +static void +run_validity_tests (const ValidityTest *tests, +                    int                 n_tests, +                    DBusValidity (* func) (const DBusString*,int,int)) +{ +  int i; + +  for (i = 0; i < n_tests; i++) +    { +      DBusString str; +      DBusValidity v; + +      _dbus_string_init_const (&str, tests[i].data); + +      v = (*func) (&str, 0, _dbus_string_get_length (&str)); + +      if (v != tests[i].expected) +        { +          _dbus_warn ("Improper validation result %d for '%s'\n", +                      v, tests[i].data); +          _dbus_assert_not_reached ("test failed"); +        } + +      ++i; +    } +} + +static const ValidityTest signature_tests[] = { +  { "", DBUS_VALID }, +  { "i", DBUS_VALID }, +  { "ai", DBUS_VALID }, +  { "(i)", DBUS_VALID }, +  { "q", DBUS_INVALID_UNKNOWN_TYPECODE }, +  { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, +  { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, +  { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, +  { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, +  /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */ +  { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", +    DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION }, +  { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))", +    DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION }, +  { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, +  { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, +  { "a)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, +  { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, +  { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, +  { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, +  { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, +  { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, +  { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, +  { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, +  { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, +  { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS } +}; +  dbus_bool_t  _dbus_marshal_validate_test (void)  { +  DBusString str; +  int i; + +  const char *valid_paths[] = { +    "/", +    "/foo/bar", +    "/foo", +    "/foo/bar/baz" +  }; +  const char *invalid_paths[] = { +    "bar", +    "bar/baz", +    "/foo/bar/", +    "/foo/" +    "foo/", +    "boo//blah", +    "//", +    "///", +    "foo///blah/", +    "Hello World", +    "", +    "   ", +    "foo bar" +  }; + +  const char *valid_interfaces[] = { +    "org.freedesktop.Foo", +    "Bar.Baz", +    "Blah.Blah.Blah.Blah.Blah", +    "a.b", +    "a.b.c.d.e.f.g", +    "a0.b1.c2.d3.e4.f5.g6", +    "abc123.foo27" +  }; +  const char *invalid_interfaces[] = { +    ".", +    "", +    "..", +    ".Foo.Bar", +    "..Foo.Bar", +    "Foo.Bar.", +    "Foo.Bar..", +    "Foo", +    "9foo.bar.baz", +    "foo.bar..baz", +    "foo.bar...baz", +    "foo.bar.b..blah", +    ":", +    ":0-1", +    "10", +    ":11.34324", +    "0.0.0", +    "0..0", +    "foo.Bar.%", +    "foo.Bar!!", +    "!Foo.bar.bz", +    "foo.$.blah", +    "", +    "   ", +    "foo bar" +  }; + +  const char *valid_base_services[] = { +    ":0", +    ":a", +    ":", +    ":.a", +    ":.1", +    ":0.1", +    ":000.2222", +    ":.blah", +    ":abce.freedesktop.blah" +  }; +  const char *invalid_base_services[] = { +    ":-", +    ":!", +    ":0-10", +    ":blah.", +    ":blah.", +    ":blah..org", +    ":blah.org..", +    ":..blah.org", +    "", +    "   ", +    "foo bar" +  }; + +  const char *valid_members[] = { +    "Hello", +    "Bar", +    "foobar", +    "_foobar", +    "foo89" +  }; + +  const char *invalid_members[] = { +    "9Hello", +    "10", +    "1", +    "foo-bar", +    "blah.org", +    ".blah", +    "blah.", +    "Hello.", +    "!foo", +    "", +    "   ", +    "foo bar" +  }; + +  const char *valid_signatures[] = { +    "", +    "sss", +    "i", +    "b" +  }; + +  const char *invalid_signatures[] = { +    " ", +    "not a valid signature", +    "123", +    ".", +    "(" +  }; + +  /* Signature with reason */ + +  run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests), +                      _dbus_validate_signature_with_reason); + +  /* Path validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_paths)) +    { +      _dbus_string_init_const (&str, valid_paths[i]); + +      if (!_dbus_validate_path (&str, 0, +                                _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]); +          _dbus_assert_not_reached ("invalid path"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths)) +    { +      _dbus_string_init_const (&str, invalid_paths[i]); + +      if (_dbus_validate_path (&str, 0, +                               _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]); +          _dbus_assert_not_reached ("valid path"); +        } + +      ++i; +    } + +  /* Interface validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) +    { +      _dbus_string_init_const (&str, valid_interfaces[i]); + +      if (!_dbus_validate_interface (&str, 0, +                                     _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]); +          _dbus_assert_not_reached ("invalid interface"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) +    { +      _dbus_string_init_const (&str, invalid_interfaces[i]); + +      if (_dbus_validate_interface (&str, 0, +                                    _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]); +          _dbus_assert_not_reached ("valid interface"); +        } + +      ++i; +    } + +  /* Service validation (check that valid interfaces are valid services, +   * and invalid interfaces are invalid services except if they start with ':') +   */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) +    { +      _dbus_string_init_const (&str, valid_interfaces[i]); + +      if (!_dbus_validate_service (&str, 0, +                                   _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Service \"%s\" should have been valid\n", valid_interfaces[i]); +          _dbus_assert_not_reached ("invalid service"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) +    { +      if (invalid_interfaces[i][0] != ':') +        { +          _dbus_string_init_const (&str, invalid_interfaces[i]); + +          if (_dbus_validate_service (&str, 0, +                                      _dbus_string_get_length (&str))) +            { +              _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_interfaces[i]); +              _dbus_assert_not_reached ("valid service"); +            } +        } + +      ++i; +    } + +  /* Base service validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_base_services)) +    { +      _dbus_string_init_const (&str, valid_base_services[i]); + +      if (!_dbus_validate_service (&str, 0, +                                   _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Service \"%s\" should have been valid\n", valid_base_services[i]); +          _dbus_assert_not_reached ("invalid base service"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_base_services)) +    { +      _dbus_string_init_const (&str, invalid_base_services[i]); + +      if (_dbus_validate_service (&str, 0, +                                  _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_base_services[i]); +          _dbus_assert_not_reached ("valid base service"); +        } + +      ++i; +    } + + +  /* Error name validation (currently identical to interfaces) +   */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) +    { +      _dbus_string_init_const (&str, valid_interfaces[i]); + +      if (!_dbus_validate_error_name (&str, 0, +                                      _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]); +          _dbus_assert_not_reached ("invalid error name"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) +    { +      if (invalid_interfaces[i][0] != ':') +        { +          _dbus_string_init_const (&str, invalid_interfaces[i]); + +          if (_dbus_validate_error_name (&str, 0, +                                         _dbus_string_get_length (&str))) +            { +              _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]); +              _dbus_assert_not_reached ("valid error name"); +            } +        } + +      ++i; +    } + +  /* Member validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_members)) +    { +      _dbus_string_init_const (&str, valid_members[i]); + +      if (!_dbus_validate_member (&str, 0, +                                  _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]); +          _dbus_assert_not_reached ("invalid member"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_members)) +    { +      _dbus_string_init_const (&str, invalid_members[i]); + +      if (_dbus_validate_member (&str, 0, +                                 _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]); +          _dbus_assert_not_reached ("valid member"); +        } + +      ++i; +    } + +  /* Signature validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_signatures)) +    { +      _dbus_string_init_const (&str, valid_signatures[i]); + +      if (!_dbus_validate_signature (&str, 0, +                                     _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]); +          _dbus_assert_not_reached ("invalid signature"); +        } + +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures)) +    { +      _dbus_string_init_const (&str, invalid_signatures[i]); + +      if (_dbus_validate_signature (&str, 0, +                                    _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]); +          _dbus_assert_not_reached ("valid signature"); +        } + +      ++i; +    } + +  /* Validate claimed length longer than real length */ +  _dbus_string_init_const (&str, "abc.efg"); +  if (_dbus_validate_service (&str, 0, 8)) +    _dbus_assert_not_reached ("validated too-long string"); +  if (_dbus_validate_interface (&str, 0, 8)) +    _dbus_assert_not_reached ("validated too-long string"); +  if (_dbus_validate_error_name (&str, 0, 8)) +    _dbus_assert_not_reached ("validated too-long string"); + +  _dbus_string_init_const (&str, "abc"); +  if (_dbus_validate_member (&str, 0, 4)) +    _dbus_assert_not_reached ("validated too-long string"); + +  _dbus_string_init_const (&str, "sss"); +  if (_dbus_validate_signature (&str, 0, 4)) +    _dbus_assert_not_reached ("validated too-long signature"); + +  /* Validate string exceeding max name length */ +  if (!_dbus_string_init (&str)) +    _dbus_assert_not_reached ("no memory"); + +  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) +    if (!_dbus_string_append (&str, "abc.def")) +      _dbus_assert_not_reached ("no memory"); + +  if (_dbus_validate_service (&str, 0, _dbus_string_get_length (&str))) +    _dbus_assert_not_reached ("validated overmax string"); +  if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str))) +    _dbus_assert_not_reached ("validated overmax string"); +  if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str))) +    _dbus_assert_not_reached ("validated overmax string"); + +  /* overlong member */ +  _dbus_string_set_length (&str, 0); +  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) +    if (!_dbus_string_append (&str, "abc")) +      _dbus_assert_not_reached ("no memory"); + +  if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str))) +    _dbus_assert_not_reached ("validated overmax string"); + +  /* overlong base service */ +  _dbus_string_set_length (&str, 0); +  _dbus_string_append (&str, ":"); +  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) +    if (!_dbus_string_append (&str, "abc")) +      _dbus_assert_not_reached ("no memory"); + +  if (_dbus_validate_service (&str, 0, _dbus_string_get_length (&str))) +    _dbus_assert_not_reached ("validated overmax string"); + +  _dbus_string_free (&str);    return TRUE;  } diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h index 86cbf7ea..8f4e7ef6 100644 --- a/dbus/dbus-marshal-validate.h +++ b/dbus/dbus-marshal-validate.h @@ -31,5 +31,133 @@  #error "config.h not included here"  #endif +/** + * This is primarily used in unit testing, so we can verify that each + * invalid message is invalid for the expected reasons. Thus we really + * want a distinct enum value for every codepath leaving the validator + * functions. Enum values are specified manually for ease of debugging + * (so you can see the enum value given a printf) + */ +typedef enum +{ +  DBUS_VALID = 0, +  DBUS_INVALID_UNKNOWN_TYPECODE = 1, +  DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE = 2, +  DBUS_INVALID_SIGNATURE_TOO_LONG = 3, +  DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION = 4, +  DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION = 5, +  DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED = 6, +  DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED = 7, +  DBUS_INVALID_STRUCT_HAS_NO_FIELDS = 8, +  DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL = 9, +  DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE = 10, +  DBUS_INVALID_NOT_ENOUGH_DATA = 11, +  DBUS_INVALID_TOO_MUCH_DATA = 12, +  DBUS_INVALID_BAD_BYTE_ORDER = 13, +  DBUS_INVALID_BAD_PROTOCOL_VERSION = 14, +  DBUS_INVALID_BAD_MESSAGE_TYPE = 15, +  DBUS_INVALID_BAD_SERIAL = 16, +  DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH = 17, +  DBUS_INVALID_INSANE_BODY_LENGTH = 18, +  DBUS_INVALID_MESSAGE_TOO_LONG = 19, +  DBUS_INVALID_HEADER_FIELD_CODE = 20, +  DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE = 21, +  DBUS_INVALID_USES_LOCAL_INTERFACE = 22, +  DBUS_INVALID_USES_LOCAL_PATH = 23, +  DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE = 24, +  DBUS_INVALID_BAD_DESTINATION = 25, +  DBUS_INVALID_BAD_INTERFACE = 26, +  DBUS_INVALID_BAD_MEMBER = 27, +  DBUS_INVALID_BAD_ERROR_NAME = 28, +  DBUS_INVALID_BAD_SENDER = 29, +  DBUS_INVALID_MISSING_PATH = 30, +  DBUS_INVALID_MISSING_INTERFACE = 31, +  DBUS_INVALID_MISSING_MEMBER = 32, +  DBUS_INVALID_MISSING_ERROR_NAME = 33, +  DBUS_INVALID_MISSING_REPLY_SERIAL = 34, +  DBUS_INVALID_STRING_LENGTH_OUT_OF_BOUNDS = 35, +  DBUS_INVALID_ARRAY_LENGTH_OUT_OF_BOUNDS = 36, +  DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM = 37, +  DBUS_INVALID_BAD_PATH = 38, +  DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 39, +  DBUS_INVALID_BAD_SIGNATURE = 40, +  DBUS_INVALID_BAD_UTF8_IN_STRING = 41, +  DBUS_INVALID_ARRAY_LENGTH_INCORRECT = 42, +  DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 43, +  DBUS_INVALID_VARIANT_SIGNATURE_BAD = 44, +  DBUS_INVALID_VARIANT_SIGNATURE_EMPTY = 45, +  DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES = 46, +  DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL = 47, +  DBUS_INVALID_STRING_MISSING_NUL = 48, +  DBUS_INVALID_SIGNATURE_MISSING_NUL = 49, +} DBusValidity; + +DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str, +                                                   int               type_pos, +                                                   int               len); +DBusValidity _dbus_validate_body_with_reason      (const DBusString *expected_signature, +                                                   int               expected_signature_start, +                                                   int               byte_order, +                                                   int              *bytes_remaining, +                                                   const DBusString *value_str, +                                                   int               value_pos, +                                                   int               len); + +dbus_bool_t _dbus_validate_path       (const DBusString *str, +                                       int               start, +                                       int               len); +dbus_bool_t _dbus_validate_interface  (const DBusString *str, +                                       int               start, +                                       int               len); +dbus_bool_t _dbus_validate_member     (const DBusString *str, +                                       int               start, +                                       int               len); +dbus_bool_t _dbus_validate_error_name (const DBusString *str, +                                       int               start, +                                       int               len); +dbus_bool_t _dbus_validate_service    (const DBusString *str, +                                       int               start, +                                       int               len); +dbus_bool_t _dbus_validate_signature  (const DBusString *str, +                                       int               start, +                                       int               len); + +#ifdef DBUS_DISABLE_CHECKS + +/* Be sure they don't exist, since we don't want to use them outside of checks + * and so we want the compile failure. + */ +#define DECLARE_DBUS_NAME_CHECK(what) +#define DEFINE_DBUS_NAME_CHECK(what) + +#else /* !DBUS_DISABLE_CHECKS */ + +/* A name check is used in _dbus_return_if_fail(), it's not suitable + * for validating untrusted data. use _dbus_validate_##what for that. + */ +#define DECLARE_DBUS_NAME_CHECK(what) \ +dbus_bool_t _dbus_check_is_valid_##what (const char *name) + +#define DEFINE_DBUS_NAME_CHECK(what)                                    \ +dbus_bool_t                                                             \ +_dbus_check_is_valid_##what (const char *name)                          \ +{                                                                       \ +  DBusString str;                                                       \ +                                                                        \ +  if (name == NULL)                                                     \ +    return FALSE;                                                       \ +                                                                        \ +  _dbus_string_init_const (&str, name);                                 \ +  return _dbus_validate_##what (&str, 0,                                \ +                                _dbus_string_get_length (&str));        \ +} +#endif /* !DBUS_DISABLE_CHECKS */ + +DECLARE_DBUS_NAME_CHECK(path); +DECLARE_DBUS_NAME_CHECK(interface); +DECLARE_DBUS_NAME_CHECK(member); +DECLARE_DBUS_NAME_CHECK(error_name); +DECLARE_DBUS_NAME_CHECK(service); +DECLARE_DBUS_NAME_CHECK(signature);  #endif /* DBUS_MARSHAL_VALIDATE_H */ diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c deleted file mode 100644 index 00821daf..00000000 --- a/dbus/dbus-marshal.c +++ /dev/null @@ -1,2941 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-marshal.c  Marshalling routines - * - * Copyright (C) 2002 CodeFactory AB - * Copyright (C) 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-marshal.h" -#include "dbus-internals.h" -#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 -#include "dbus-string-private.h" - -#include <string.h> - -/** - * @defgroup DBusMarshal marshaling and unmarshaling - * @ingroup  DBusInternals - * @brief functions to marshal/unmarshal data from the wire - * - * Types and functions related to converting primitive data types from - * wire format to native machine format, and vice versa. - * - * @{ - */ - -static dbus_uint32_t -unpack_4_octets (int                  byte_order, -                 const unsigned char *data) -{ -  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); -   -  if (byte_order == DBUS_LITTLE_ENDIAN) -    return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data); -  else -    return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data); -} - -#ifndef DBUS_HAVE_INT64 -/* from ORBit */ -static void -swap_bytes (unsigned char *data, -            unsigned int   len) -{ -  unsigned char *p1 = data; -  unsigned char *p2 = data + len - 1; - -  while (p1 < p2) -    { -      unsigned char tmp = *p1; -      *p1 = *p2; -      *p2 = tmp; - -      --p2; -      ++p1; -    } -} -#endif /* !DBUS_HAVE_INT64 */ - -/** - * Union used to manipulate 8 bytes as if they - * were various types.  - */ -typedef union -{ -#ifdef DBUS_HAVE_INT64 -  dbus_int64_t  s; /**< 64-bit integer */ -  dbus_uint64_t u; /**< 64-bit unsinged integer */ -#endif -  double d;        /**< double */ -} DBusOctets8; - -static DBusOctets8 -unpack_8_octets (int                  byte_order, -                 const unsigned char *data) -{ -  DBusOctets8 r; -   -  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data); -  _dbus_assert (sizeof (r) == 8); -   -#ifdef DBUS_HAVE_INT64 -  if (byte_order == DBUS_LITTLE_ENDIAN) -    r.u = DBUS_UINT64_FROM_LE (*(dbus_uint64_t*)data); -  else -    r.u = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data); -#else -  r.d = *(double*)data; -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    swap_bytes ((unsigned char*) &r, sizeof (r)); -#endif -   -  return r; -} - -/** - * Unpacks a 32 bit unsigned integer from a data pointer - * - * @param byte_order The byte order to use - * @param data the data pointer - * @returns the integer - */ -dbus_uint32_t -_dbus_unpack_uint32 (int                  byte_order, -                     const unsigned char *data) -{ -  return unpack_4_octets (byte_order, data); -}   - -/** - * 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) unpack_4_octets (byte_order, data); -} - -#ifdef DBUS_HAVE_INT64 -/** - * Unpacks a 64 bit unsigned integer from a data pointer - * - * @param byte_order The byte order to use - * @param data the data pointer - * @returns the integer - */ -dbus_uint64_t -_dbus_unpack_uint64 (int                  byte_order, -                     const unsigned char *data) -{ -  DBusOctets8 r; -   -  r = unpack_8_octets (byte_order, data); - -  return r.u; -}   - -/** - * Unpacks a 64 bit signed integer from a data pointer - * - * @param byte_order The byte order to use - * @param data the data pointer - * @returns the integer - */ -dbus_int64_t -_dbus_unpack_int64 (int                  byte_order, -                    const unsigned char *data) -{ -  DBusOctets8 r; -   -  r = unpack_8_octets (byte_order, data); - -  return r.s; -} - -#endif /* DBUS_HAVE_INT64 */ - -static void -pack_4_octets (dbus_uint32_t   value, -               int             byte_order, -               unsigned char  *data) -{ -  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); -   -  if ((byte_order) == DBUS_LITTLE_ENDIAN)                   -    *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);        -  else -    *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value); -} - -static void -pack_8_octets (DBusOctets8     value, -               int             byte_order, -               unsigned char  *data) -{ -  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data); - -#ifdef DBUS_HAVE_INT64 -  if ((byte_order) == DBUS_LITTLE_ENDIAN)                   -    *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_LE (value.u);  -  else -    *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_BE (value.u); -#else -  memcpy (data, &value, 8); -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    swap_bytes ((unsigned char *)data, 8); -#endif -} - -/** - * Packs a 32 bit unsigned 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_uint32 (dbus_uint32_t   value, -                   int             byte_order, -                   unsigned char  *data) -{ -  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); -} - -#ifdef DBUS_HAVE_INT64 -/** - * Packs a 64 bit unsigned 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_uint64 (dbus_uint64_t   value, -                   int             byte_order, -                   unsigned char  *data) -{ -  DBusOctets8 r; -  r.u = value; -  pack_8_octets (r, byte_order, data); -} - -/** - * Packs a 64 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_int64 (dbus_int64_t   value, -                  int            byte_order, -                  unsigned char *data) -{ -  DBusOctets8 r; -  r.s = value; -  pack_8_octets (r, byte_order, data); -} -#endif /* DBUS_HAVE_INT64 */ - -static void -set_4_octets (DBusString          *str, -              int                  byte_order, -              int                  offset, -              dbus_uint32_t        value) -{ -  char *data; -   -  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || -                byte_order == DBUS_BIG_ENDIAN); -   -  data = _dbus_string_get_data_len (str, offset, 4); - -  _dbus_pack_uint32 (value, byte_order, data); -} - -static void -set_8_octets (DBusString          *str, -              int                  byte_order, -              int                  offset, -              DBusOctets8          value) -{ -  char *data; -   -  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || -                byte_order == DBUS_BIG_ENDIAN); -   -  data = _dbus_string_get_data_len (str, offset, 8); - -  pack_8_octets (value, byte_order, data); -} - -/** - * Sets the 4 bytes at the given offset to a marshaled signed integer, - * replacing anything found there previously. - * - * @param str the string to write the marshalled int to - * @param offset the byte offset where int should be written - * @param byte_order the byte order to use - * @param value the value - *  - */ -void -_dbus_marshal_set_int32 (DBusString          *str, -                         int                  byte_order, -                         int                  offset, -                         dbus_int32_t         value) -{ -  set_4_octets (str, byte_order, offset, (dbus_uint32_t) value); -} - -/** - * Sets the 4 bytes at the given offset to a marshaled unsigned - * integer, replacing anything found there previously. - * - * @param str the string to write the marshalled int to - * @param offset the byte offset where int should be written - * @param byte_order the byte order to use - * @param value the value - *  - */ -void -_dbus_marshal_set_uint32 (DBusString          *str, -                          int                  byte_order, -                          int                  offset, -                          dbus_uint32_t        value) -{ -  set_4_octets (str, byte_order, offset, value); -} - -#ifdef DBUS_HAVE_INT64 - -/** - * Sets the 8 bytes at the given offset to a marshaled signed integer, - * replacing anything found there previously. - * - * @param str the string to write the marshalled int to - * @param offset the byte offset where int should be written - * @param byte_order the byte order to use - * @param value the value - *  - */ -void -_dbus_marshal_set_int64 (DBusString          *str, -                         int                  byte_order, -                         int                  offset, -                         dbus_int64_t         value) -{ -  DBusOctets8 r; -  r.s = value; -  set_8_octets (str, byte_order, offset, r); -} - -/** - * Sets the 8 bytes at the given offset to a marshaled unsigned - * integer, replacing anything found there previously. - * - * @param str the string to write the marshalled int to - * @param offset the byte offset where int should be written - * @param byte_order the byte order to use - * @param value the value - *  - */ -void -_dbus_marshal_set_uint64 (DBusString          *str, -                          int                  byte_order, -                          int                  offset, -                          dbus_uint64_t        value) -{ -  DBusOctets8 r; -  r.u = value; -  set_8_octets (str, byte_order, offset, r); -} -#endif /* DBUS_HAVE_INT64 */ - -/** - * Sets the existing marshaled string at the given offset with - * a new marshaled string. The given offset must point to - * an existing string or the wrong length will be deleted - * and replaced with the new string. - * - * Note: no attempt is made by this function to re-align - * any data which has been already marshalled after this - * string. Use with caution. - * - * @param str the string to write the marshalled string to - * @param offset the byte offset where string should be written - * @param byte_order the byte order to use - * @param value the value - * @param len the length to use - * @returns #TRUE on success - *  - */ -dbus_bool_t -_dbus_marshal_set_string (DBusString          *str, -                          int                  byte_order, -                          int                  offset, -                          const DBusString    *value, -			  int                  len) -{ -  int old_len; -   -  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || -                byte_order == DBUS_BIG_ENDIAN); -   -  old_len = _dbus_demarshal_uint32 (str, byte_order, -                                    offset, NULL); - -  if (!_dbus_string_replace_len (value, 0, len, -                                 str, offset + 4, old_len)) -    return FALSE; - -  _dbus_marshal_set_uint32 (str, byte_order, -                            offset, len); - -  return TRUE; -} - -/** - * Sets the existing marshaled object path at the given offset to a new - * value. The given offset must point to an existing object path or this - * function doesn't make sense. - * - * @todo implement this function - * - * @param str the string to write the marshalled path to - * @param offset the byte offset where path should be written - * @param byte_order the byte order to use - * @param path the new path - * @param path_len number of elements in the path - */ -void -_dbus_marshal_set_object_path (DBusString         *str, -                               int                 byte_order, -                               int                 offset, -                               const char        **path, -                               int                 path_len) -{ - -  /* FIXME */ -} - -static dbus_bool_t -marshal_4_octets (DBusString   *str, -                  int           byte_order, -                  dbus_uint32_t value) -{ -  _dbus_assert (sizeof (value) == 4); -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    value = DBUS_UINT32_SWAP_LE_BE (value); - -  return _dbus_string_append_4_aligned (str, -                                        (const unsigned char *)&value); -} - -static dbus_bool_t -marshal_8_octets (DBusString *str, -                  int         byte_order, -                  DBusOctets8 value) -{ -  _dbus_assert (sizeof (value) == 8); -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    pack_8_octets (value, byte_order, (unsigned char*) &value); /* pack into self, swapping as we go */ - -  return _dbus_string_append_8_aligned (str, -                                        (const unsigned char *)&value); -} - -/** - * Marshals a double value. - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the value - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_double (DBusString *str, -		      int         byte_order, -		      double      value) -{ -  DBusOctets8 r; -  r.d = value; -  return marshal_8_octets (str, byte_order, r); -} - -/** - * Marshals a 32 bit signed integer value. - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the value - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_int32  (DBusString   *str, -		      int           byte_order, -		      dbus_int32_t  value) -{ -  return marshal_4_octets (str, byte_order, (dbus_uint32_t) value); -} - -/** - * Marshals a 32 bit unsigned integer value. - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the value - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_uint32 (DBusString    *str, -		      int            byte_order, -		      dbus_uint32_t  value) -{ -  return marshal_4_octets (str, byte_order, value); -} - - -#ifdef DBUS_HAVE_INT64 -/** - * Marshals a 64 bit signed integer value. - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the value - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_int64  (DBusString   *str, -		      int           byte_order, -		      dbus_int64_t  value) -{ -  DBusOctets8 r; -  r.s = value; -  return marshal_8_octets (str, byte_order, r); -} - -/** - * Marshals a 64 bit unsigned integer value. - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the value - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_uint64 (DBusString    *str, -		      int            byte_order, -		      dbus_uint64_t  value) -{ -  DBusOctets8 r; -  r.u = value; -  return marshal_8_octets (str, byte_order, r); -} - -#endif /* DBUS_HAVE_INT64 */ - -/** - * Marshals a UTF-8 string - * - * @todo: If the string append fails we need to restore - * the old length. (also for other marshallers) - *  - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the string - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_string (DBusString    *str, -		      int            byte_order, -		      const char    *value) -{ -  int len, old_string_len; - -  old_string_len = _dbus_string_get_length (str); -   -  len = strlen (value); - -  if (!_dbus_marshal_uint32 (str, byte_order, len)) -    { -      /* Restore the previous length */ -      _dbus_string_set_length (str, old_string_len); - -      return FALSE; -    } - -  return _dbus_string_append_len (str, value, len + 1); -} - -/** - * Marshals a UTF-8 string - * - * @todo: If the string append fails we need to restore - * the old length. (also for other marshallers) - *  - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the string - * @param len length of string to marshal in bytes - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_string_len (DBusString    *str, -                          int            byte_order, -                          const char    *value, -                          int            len) -{ -  int old_string_len; - -  old_string_len = _dbus_string_get_length (str); - -  if (!_dbus_marshal_uint32 (str, byte_order, len)) -    { -      /* Restore the previous length */ -      _dbus_string_set_length (str, old_string_len); - -      return FALSE; -    } - -  if (!_dbus_string_append_len (str, value, len)) -    return FALSE; - -  /* add a nul byte */ -  if (!_dbus_string_lengthen (str, 1)) -    return FALSE; - -  return TRUE; -} - -/** - * Marshals a byte array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len number of elements in the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_byte_array (DBusString          *str, -			  int                  byte_order, -			  const unsigned char *value, -			  int                  len) -{ -  int old_string_len; - -  old_string_len = _dbus_string_get_length (str); -   -  if (!_dbus_marshal_uint32 (str, byte_order, len)) -    { -      /* Restore the previous length */ -      _dbus_string_set_length (str, old_string_len); - -      return FALSE; -    } - -  if (len == 0) -    return TRUE; -  else -    return _dbus_string_append_len (str, value, len); -} - -static dbus_bool_t -marshal_4_octets_array (DBusString          *str, -                        int                  byte_order, -                        const dbus_uint32_t *value, -                        int                  len) -{ -  int old_string_len; -  int array_start; - -  old_string_len = _dbus_string_get_length (str); - -  if (!_dbus_marshal_uint32 (str, byte_order, len * 4)) -    goto error; - -  array_start = _dbus_string_get_length (str); -   -  if (!_dbus_string_append_len (str, (const unsigned char*) value, -                                len * 4)) -    goto error; -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    { -      const unsigned char *d; -      const unsigned char *end; -       -      d = _dbus_string_get_data (str) + array_start; -      end = d + len * 4; -      while (d != end) -        { -          *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d)); -          d += 4; -        } -    } - -  return TRUE; -   - error: -  /* Restore previous length */ -  _dbus_string_set_length (str, old_string_len); -   -  return FALSE;   -} - -static dbus_bool_t -marshal_8_octets_array (DBusString          *str, -                        int                  byte_order, -                        const DBusOctets8   *value, -                        int                  len) -{ -  int old_string_len; -  int array_start; - -  old_string_len = _dbus_string_get_length (str); - -  if (!_dbus_marshal_uint32 (str, byte_order, len * 8)) -    goto error; - -  array_start = _dbus_string_get_length (str); -   -  if (!_dbus_string_append_len (str, (const unsigned char*) value, -                                len * 8)) -    goto error; -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    { -      const unsigned char *d; -      const unsigned char *end; -       -      d = _dbus_string_get_data (str) + array_start; -      end = d + len * 8; -      while (d != end) -        { -#ifdef DBUS_HAVE_INT64 -          *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); -#else -          swap_bytes ((unsigned char*) d, 8); -#endif -          d += 8; -        } -    } - -  return TRUE; -   - error: -  /* Restore previous length */ -  _dbus_string_set_length (str, old_string_len); -   -  return FALSE;   -} - -/** - * Marshals a 32 bit signed integer array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_int32_array (DBusString         *str, -			   int                 byte_order, -			   const dbus_int32_t *value, -			   int                 len) -{ -  return marshal_4_octets_array (str, byte_order, -                                 (const dbus_uint32_t*) value, -                                 len); -} - -/** - * Marshals a 32 bit unsigned integer array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_uint32_array (DBusString          *str, -			    int                  byte_order, -			    const dbus_uint32_t  *value, -			    int                  len) -{ -  return marshal_4_octets_array (str, byte_order, -                                 value, -                                 len); -} - -#ifdef DBUS_HAVE_INT64 - -/** - * Marshals a 64 bit signed integer array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_int64_array (DBusString         *str, -			   int                 byte_order, -			   const dbus_int64_t *value, -			   int                 len) -{ -  return marshal_8_octets_array (str, byte_order, -                                 (const DBusOctets8*) value, -                                 len); -} - -/** - * Marshals a 64 bit unsigned integer array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_uint64_array (DBusString          *str, -			    int                  byte_order, -			    const dbus_uint64_t  *value, -			    int                  len) -{ -  return marshal_8_octets_array (str, byte_order, -                                 (const DBusOctets8*) value, -                                 len); -} - -#endif /* DBUS_HAVE_INT64 */ - -/** - * Marshals a double array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_double_array (DBusString          *str, -			    int                  byte_order, -			    const double        *value, -			    int                  len) -{ -  return marshal_8_octets_array (str, byte_order, -                                 (const DBusOctets8*) value, -                                 len); -} - -/** - * Marshals a string array - * - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_string_array (DBusString  *str, -			    int          byte_order, -			    const char **value, -			    int          len) -{ -  int i, old_string_len, array_start; - -  old_string_len = _dbus_string_get_length (str); - -  /* Set the length to 0 temporarily */ -  if (!_dbus_marshal_uint32 (str, byte_order, 0)) -    goto error; - -  array_start = _dbus_string_get_length (str); -   -  for (i = 0; i < len; i++) -    if (!_dbus_marshal_string (str, byte_order, value[i])) -      goto error; - -  /* Write the length now that we know it */ -  _dbus_marshal_set_uint32 (str, byte_order, -			    _DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)), -			    _dbus_string_get_length (str) - array_start); -   -  return TRUE; -   - error: -  /* Restore previous length */ -  _dbus_string_set_length (str, old_string_len); -   -  return FALSE;       -} - -/** - * Marshals an object path value. - *  - * @param str the string to append the marshalled value to - * @param byte_order the byte order to use - * @param path the path - * @param path_len length of the path - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_marshal_object_path (DBusString            *str, -                           int                    byte_order, -                           const char           **path, -                           int                    path_len) -{ -  int array_start, old_string_len; -  int i; -   -  old_string_len = _dbus_string_get_length (str); -   -  /* Set the length to 0 temporarily */ -  if (!_dbus_marshal_uint32 (str, byte_order, 0)) -    goto nomem; - -  array_start = _dbus_string_get_length (str); -   -  i = 0; -  while (i < path_len) -    { -      if (!_dbus_string_append_byte (str, '/')) -        goto nomem; -       -      if (!_dbus_string_append (str, path[0])) -        goto nomem; - -      ++i; -    } - -  /* Write the length now that we know it */ -  _dbus_marshal_set_uint32 (str, byte_order, -			    _DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)), -			    _dbus_string_get_length (str) - array_start);   - -  return TRUE; - - nomem: -  /* Restore the previous length */ -  _dbus_string_set_length (str, old_string_len); -   -  return FALSE; -} - -static dbus_uint32_t -demarshal_4_octets (const DBusString *str, -                    int               byte_order, -                    int               pos, -                    int              *new_pos) -{ -  const DBusRealString *real = (const DBusRealString*) str; -   -  pos = _DBUS_ALIGN_VALUE (pos, 4); -   -  if (new_pos) -    *new_pos = pos + 4; - -  return unpack_4_octets (byte_order, real->str + pos); -} - -static DBusOctets8 -demarshal_8_octets (const DBusString *str, -                    int               byte_order, -                    int               pos, -                    int              *new_pos) -{ -  const DBusRealString *real = (const DBusRealString*) str; -   -  pos = _DBUS_ALIGN_VALUE (pos, 8); -   -  if (new_pos) -    *new_pos = pos + 8; - -  return unpack_8_octets (byte_order, real->str + pos); -} - -/** - * Demarshals a double. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled double. - */ -double -_dbus_demarshal_double (const DBusString  *str, -			int                byte_order, -			int                pos, -			int               *new_pos) -{ -  DBusOctets8 r; - -  r = demarshal_8_octets (str, byte_order, pos, new_pos); - -  return r.d; -} - -/** - * Demarshals a 32 bit signed integer. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled integer. - */ -dbus_int32_t -_dbus_demarshal_int32  (const DBusString *str, -			int               byte_order, -			int               pos, -			int              *new_pos) -{ -  return (dbus_int32_t) demarshal_4_octets (str, byte_order, pos, new_pos); -} - -/** - * Demarshals a 32 bit unsigned integer. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled integer. - */ -dbus_uint32_t -_dbus_demarshal_uint32  (const DBusString *str, -			 int         byte_order, -			 int         pos, -			 int        *new_pos) -{ -  return demarshal_4_octets (str, byte_order, pos, new_pos); -} - -#ifdef DBUS_HAVE_INT64 - -/** - * Demarshals a 64 bit signed integer. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled integer. - */ -dbus_int64_t -_dbus_demarshal_int64  (const DBusString *str, -			int               byte_order, -			int               pos, -			int              *new_pos) -{ -  DBusOctets8 r; - -  r = demarshal_8_octets (str, byte_order, pos, new_pos); - -  return r.s; -} - -/** - * Demarshals a 64 bit unsigned integer. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled integer. - */ -dbus_uint64_t -_dbus_demarshal_uint64  (const DBusString *str, -			 int         byte_order, -			 int         pos, -			 int        *new_pos) -{ -  DBusOctets8 r; - -  r = demarshal_8_octets (str, byte_order, pos, new_pos); - -  return r.u; -} - -#endif /* DBUS_HAVE_INT64 */ - -/** - * Demarshals a basic type - * - * @param str the string containing the data - * @param type type of value to demarshal - * @param value pointer to return value data - * @param byte_order the byte order - * @param pos pointer to position in the string, - *            updated on return to new position - **/ -void -_dbus_demarshal_basic_type (const DBusString      *str, -			    int                    type, -			    void                  *value, -			    int                    byte_order, -			    int                   *pos) -{ -  const char *str_data = _dbus_string_get_const_data (str); - -  switch (type) -    { -    case DBUS_TYPE_BYTE: -    case DBUS_TYPE_BOOLEAN: -      *(unsigned char *) value = _dbus_string_get_byte (str, *pos); -      (*pos)++; -      break; -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      *pos = _DBUS_ALIGN_VALUE (*pos, 4); -      *(dbus_uint32_t *) value = *(dbus_uint32_t *)(str_data + *pos); -      if (byte_order != DBUS_COMPILER_BYTE_ORDER) -	*(dbus_uint32_t *) value = DBUS_UINT32_SWAP_LE_BE (*(dbus_uint32_t *) value); -      *pos += 4; -      break; -#ifdef DBUS_HAVE_INT64 -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:  -#endif /* DBUS_HAVE_INT64 */ -    case DBUS_TYPE_DOUBLE: -      *pos = _DBUS_ALIGN_VALUE (*pos, 8); -      memcpy (value, str_data + *pos, 8); -      if (byte_order != DBUS_COMPILER_BYTE_ORDER) -#ifdef DBUS_HAVE_INT64 -	*(dbus_uint64_t *) value = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t *) value); -#else	 -	swap_bytes (value, 8); -#endif -      *pos += 8; -      break; -    default: -      _dbus_assert_not_reached ("not a basic type"); -      break; -    } -} - -/** - * Demarshals an UTF-8 string. - * - * @todo Should we check the string to make sure - * that it's  valid UTF-8, and maybe "fix" the string - * if it's broken? - * - * @todo Should probably demarshal to a DBusString, - * having memcpy() in here is Evil(tm). - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @returns the demarshaled string. - */ -char * -_dbus_demarshal_string (const DBusString *str, -			int               byte_order, -			int               pos, -			int              *new_pos) -{ -  int len; -  char *retval; -  const char *data; -   -  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); - -  retval = dbus_malloc (len + 1); - -  if (!retval) -    return NULL; - -  data = _dbus_string_get_const_data_len (str, pos, len + 1); - -  if (!data) -    return NULL; - -  memcpy (retval, data, len + 1); - -  if (new_pos) -    *new_pos = pos + len + 1; -   -  return retval; -} - -/** - * Demarshals a byte array. - * - * @todo Should probably demarshal to a DBusString, - * having memcpy() in here is Evil(tm). - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data -  - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_byte_array (const DBusString  *str, -			    int                byte_order, -			    int                pos, -			    int               *new_pos, -			    unsigned char    **array, -			    int               *array_len) -{ -  int len; -  unsigned char *retval; -  const char *data; - -  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); - -  if (len == 0) -    { -      *array_len = len; -      *array = NULL; - -      if (new_pos) -	*new_pos = pos; -       -      return TRUE; -    } -   -  retval = dbus_malloc (len); - -  if (!retval) -    return FALSE; - -  data = _dbus_string_get_const_data_len (str, pos, len); - -  if (!data) -    { -      dbus_free (retval); -      return FALSE; -    } - -  memcpy (retval, data, len); - -  if (new_pos) -    *new_pos = pos + len; - -  *array = retval; -  *array_len = len; -   -  return TRUE; -} - -static dbus_bool_t -demarshal_4_octets_array (const DBusString  *str, -                          int                byte_order, -                          int                pos, -                          int               *new_pos, -                          dbus_uint32_t    **array, -                          int               *array_len) -{ -  int len, i; -  dbus_uint32_t *retval; -  int byte_len; -   -  byte_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -  len = byte_len / 4; - -  if (len == 0) -    { -      *array_len = 0; -      *array = NULL; - -      if (new_pos) -	*new_pos = pos; -       -      return TRUE; -    } - -  if (!_dbus_string_copy_data_len (str, (char**) &retval, -                                   pos, byte_len)) -    return FALSE; -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    { -      for (i = 0; i < len; i++) -        retval[i] = DBUS_UINT32_SWAP_LE_BE (retval[i]); -    } - -  if (new_pos) -    *new_pos = pos + byte_len; - -  *array_len = len; -  *array = retval; -   -  return TRUE;   -} - -static dbus_bool_t -demarshal_8_octets_array (const DBusString  *str, -                          int                byte_order, -                          int                pos, -                          int               *new_pos, -                          DBusOctets8      **array, -                          int               *array_len) -{ -  int len, i; -  DBusOctets8 *retval; -  int byte_len; -   -  byte_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -  len = byte_len / 8; - -  if (len == 0) -    { -      *array_len = 0; -      *array = NULL; - -      if (new_pos) -	*new_pos = pos; -       -      return TRUE; -    } - -  if (!_dbus_string_copy_data_len (str, (char**) &retval, -                                   pos, byte_len)) -    return FALSE; -   -  if (byte_order != DBUS_COMPILER_BYTE_ORDER) -    { -      for (i = 0; i < len; i++) -        { -#ifdef DBUS_HAVE_INT64 -          retval[i].u = DBUS_UINT64_SWAP_LE_BE (retval[i].u); -#else -          swap_bytes ((unsigned char *) &retval[i], 8); -#endif -        } -    } - -  if (new_pos) -    *new_pos = pos + byte_len; - -  *array_len = len; -  *array = retval; -   -  return TRUE;   -} - -/** - * Demarshals a 32 bit signed integer array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_int32_array (const DBusString  *str, -			     int                byte_order, -			     int                pos, -			     int               *new_pos, -			     dbus_int32_t     **array, -			     int               *array_len) -{ -  return demarshal_4_octets_array (str, byte_order, pos, new_pos, -                                   (dbus_uint32_t**) array, array_len); -} - -/** - * Demarshals a 32 bit unsigned integer array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_uint32_array (const DBusString  *str, -			      int                byte_order, -			      int                pos, -			      int               *new_pos, -			      dbus_uint32_t    **array, -			      int               *array_len) -{ -  return demarshal_4_octets_array (str, byte_order, pos, new_pos, -                                   array, array_len); -} - -#ifdef DBUS_HAVE_INT64 - -/** - * Demarshals a 64 bit signed integer array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_int64_array (const DBusString  *str, -			     int                byte_order, -			     int                pos, -			     int               *new_pos, -			     dbus_int64_t     **array, -			     int               *array_len) -{ -  return demarshal_8_octets_array (str, byte_order, pos, new_pos, -                                   (DBusOctets8**) array, array_len); -} - -/** - * Demarshals a 64 bit unsigned integer array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_uint64_array (const DBusString  *str, -			      int                byte_order, -			      int                pos, -			      int               *new_pos, -			      dbus_uint64_t    **array, -			      int               *array_len) -{ -  return demarshal_8_octets_array (str, byte_order, pos, new_pos, -                                   (DBusOctets8**) array, array_len); -} - -#endif /* DBUS_HAVE_INT64 */ - -/** - * Demarshals a double array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len length of the demarshaled data - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_double_array (const DBusString  *str, -			      int                byte_order, -			      int                pos, -			      int               *new_pos, -			      double           **array, -			      int               *array_len) -{ -  return demarshal_8_octets_array (str, byte_order, pos, new_pos, -                                   (DBusOctets8**) array, array_len); -} - - -/** - * Demarshals an array of basic types - * - * @param str the string containing the data - * @param element_type type of array elements to demarshal - * @param array pointer to pointer to array data - * @param array_len pointer to array length - * @param byte_order the byte order - * @param pos pointer to position in the string, - *            updated on return to new position - **/ -dbus_bool_t -_dbus_demarshal_basic_type_array (const DBusString      *str, -				  int                    element_type, -				  void                 **array, -				  int                   *array_len, -				  int                    byte_order, -				  int                   *pos) -{ -  switch (element_type) -    { -    case DBUS_TYPE_BOOLEAN: -      /* FIXME: do we want to post-normalize these ? */ -    case DBUS_TYPE_BYTE: -      return _dbus_demarshal_byte_array (str, byte_order, *pos, pos, -					 (unsigned char **)array, array_len); -      break; -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      return demarshal_4_octets_array (str, byte_order, *pos, pos, -				       (dbus_uint32_t **)array, array_len); -      break; -#ifdef DBUS_HAVE_INT64 -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:  -#endif /* DBUS_HAVE_INT64 */ -    case DBUS_TYPE_DOUBLE: -      return demarshal_8_octets_array (str, byte_order, *pos, pos, -				       (DBusOctets8**) array, array_len); -    default: -      _dbus_assert_not_reached ("not a basic type"); -      break; -    } -  return FALSE; -} - -/** - * Demarshals a string array. - * - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param array the array - * @param array_len location for length of the demarshaled data or NULL - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_demarshal_string_array (const DBusString   *str, -			      int                 byte_order, -			      int                 pos, -			      int                *new_pos, -			      char             ***array, -			      int                *array_len) -{ -  int bytes_len, i; -  int len, allocated; -  int end_pos; -  char **retval; -   -  bytes_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -   -  if (bytes_len == 0) -    { -      *array_len = 0; -      *array = NULL; - -      if (new_pos) -	*new_pos = pos; -       -      return TRUE; -    } - -  len = 0; -  allocated = 4; -  end_pos = pos + bytes_len; -   -  retval = dbus_new (char *, allocated); - -  if (!retval) -    return FALSE; - -  while (pos < end_pos) -    { -      retval[len] = _dbus_demarshal_string (str, byte_order, pos, &pos); -       -      if (retval[len] == NULL) -	goto error; -       -      len += 1; - -      if (len >= allocated - 1) /* -1 for NULL termination */ -        { -          char **newp; -          newp = dbus_realloc (retval, -                               sizeof (char*) * allocated * 2); -          if (newp == NULL) -            goto error; - -          allocated *= 2; -          retval = newp; -        } -    } -       -  retval[len] = NULL; - -  if (new_pos) -    *new_pos = pos; -   -  *array = retval; -  *array_len = len; -   -  return TRUE; - - error: -  for (i = 0; i < len; i++) -    dbus_free (retval[i]); -  dbus_free (retval); - -  return FALSE; -} - -/** Set to 1 to get a bunch of spew about disassembling the path string */ -#define VERBOSE_DECOMPOSE 0 - -/** - * Decompose an object path.  A path of just "/" is - * represented as an empty vector of strings. - *  - * @param data the path data - * @param len  the length of the path string - * @param path address to store new object path - * @param path_len length of stored path - */ -dbus_bool_t -_dbus_decompose_path (const char*     data, -                      int             len, -                      char         ***path, -                      int            *path_len) -{ -  char **retval; -  int n_components; -  int i, j, comp; - -  _dbus_assert (data != NULL); - -#if VERBOSE_DECOMPOSE -  _dbus_verbose ("Decomposing path \"%s\"\n", -                 data); -#endif -   -  n_components = 0; -  i = 0; -  while (i < len) -    { -      if (data[i] == '/') -        n_components += 1; -      ++i; -    } -   -  retval = dbus_new0 (char*, n_components + 1); - -  if (retval == NULL) -    return FALSE; - -  comp = 0; -  i = 0; -  while (i < len) -    { -      if (data[i] == '/') -        ++i; -      j = i; - -      while (j < len && data[j] != '/') -        ++j; - -      /* Now [i, j) is the path component */ -      _dbus_assert (i < j); -      _dbus_assert (data[i] != '/'); -      _dbus_assert (j == len || data[j] == '/'); - -#if VERBOSE_DECOMPOSE -      _dbus_verbose ("  (component in [%d,%d))\n", -                     i, j); -#endif -       -      retval[comp] = _dbus_memdup (&data[i], j - i + 1); -      if (retval[comp] == NULL) -        { -          dbus_free_string_array (retval); -          return FALSE; -        } -      retval[comp][j-i] = '\0'; -#if VERBOSE_DECOMPOSE -      _dbus_verbose ("  (component %d = \"%s\")\n", -                     comp, retval[comp]); -#endif - -      ++comp; -      i = j; -    } -  _dbus_assert (i == len); -   -  *path = retval; -  if (path_len) -    *path_len = n_components; -   -  return TRUE; -} - -/** - * Demarshals an object path.  A path of just "/" is - * represented as an empty vector of strings. - *  - * @param str the string containing the data - * @param byte_order the byte order - * @param pos the position in the string - * @param new_pos the new position of the string - * @param path address to store new object path - * @param path_len length of stored path - */ -dbus_bool_t -_dbus_demarshal_object_path (const DBusString *str, -                             int               byte_order, -                             int               pos, -                             int              *new_pos, -                             char           ***path, -                             int              *path_len) -{ -  int len; -  const char *data; -   -  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -  data = _dbus_string_get_const_data_len (str, pos, len + 1); - -  if (!_dbus_decompose_path (data, len, path, path_len)) -    return FALSE; - -  if (new_pos) -    *new_pos = pos + len + 1; - -  return TRUE; -} - -/**  - * Returns the position right after the end of an argument.  PERFORMS - * NO VALIDATION WHATSOEVER. The message must have been previously - * validated. - * - * @param str a string - * @param byte_order the byte order to use - * @param type the type of the argument - * @param pos the pos where the arg starts - * @param end_pos pointer where the position right - * after the end position will follow - * @returns TRUE if more data exists after the arg - */ -dbus_bool_t -_dbus_marshal_get_arg_end_pos (const DBusString *str, -                               int               byte_order, -			       int               type, -                               int               pos, -                               int              *end_pos) -{ -  if (pos >= _dbus_string_get_length (str)) -    return FALSE; - -  switch (type) -    { -    case DBUS_TYPE_INVALID: -      return FALSE; -      break; - -    case DBUS_TYPE_NIL: -      *end_pos = pos; -      break; - -    case DBUS_TYPE_BYTE: -      *end_pos = pos + 1; -      break; -       -    case DBUS_TYPE_BOOLEAN: -      *end_pos = pos + 1; -      break; - -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      *end_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4; -      break; - -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64: -    case DBUS_TYPE_DOUBLE: -       -      *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8; -      break; - -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_STRING: -      { -	int len; -	 -	/* Demarshal the length */ -	len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); - -	*end_pos = pos + len + 1; -      } -      break; - -    case DBUS_TYPE_CUSTOM: -      { -	int len; -	 -	/* Demarshal the string length */ -	len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); - -	pos += len + 1; -	 -	/* Demarshal the data length */ -	len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); - -	*end_pos = pos + len; -      } -      break; -       -    case DBUS_TYPE_ARRAY: -      { -	int len; - -	/* Demarshal the length  */ -	len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -	 -	*end_pos = pos + len; -      } -      break; - -    case DBUS_TYPE_DICT: -      { -	int len; - -	/* Demarshal the length */ -	len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); -	 -	*end_pos = pos + len; -      } -      break; -       -    default: -      _dbus_warn ("Unknown message arg type %d\n", type); -      _dbus_assert_not_reached ("Unknown message argument type\n"); -      return FALSE; -    } - -  if (*end_pos > _dbus_string_get_length (str)) -    return FALSE; -   -  return TRUE; -} - -/** - * Demarshals and validates a length; returns < 0 if the validation - * fails. The length is required to be small enough that - * len*sizeof(double) will not overflow, and small enough to fit in a - * signed integer. DOES NOT check whether the length points - * beyond the end of the string, because it doesn't know the - * size of array elements. - * - * @param str the string - * @param byte_order the byte order - * @param pos the unaligned string position (snap to next aligned) - * @param new_pos return location for new position. - */ -static int -demarshal_and_validate_len (const DBusString *str, -                            int               byte_order, -                            int               pos, -                            int              *new_pos) -{ -  int align_4 = _DBUS_ALIGN_VALUE (pos, 4); -  unsigned int len; - -  _dbus_assert (new_pos != NULL); -   -  if ((align_4 + 4) > _dbus_string_get_length (str)) -    { -      _dbus_verbose ("not enough room in message for array length\n"); -      return -1; -    } -   -  if (!_dbus_string_validate_nul (str, pos, -                                  align_4 - pos)) -    { -      _dbus_verbose ("array length alignment padding not initialized to nul at %d\n", pos); -      return -1; -    } - -  len = _dbus_demarshal_uint32 (str, byte_order, align_4, new_pos); - -  /* note that the len is the number of bytes, so we need it to be -   * at least SIZE_T_MAX, but make it smaller just to keep things -   * sane.  We end up using ints for most sizes to avoid unsigned mess -   * so limit to maximum 32-bit signed int divided by at least 8, more -   * for a bit of paranoia margin. INT_MAX/32 is about 65 megabytes. -   */   -#define MAX_ARRAY_LENGTH (((unsigned int)_DBUS_INT_MAX) / 32) -  if (len > MAX_ARRAY_LENGTH) -    { -      _dbus_verbose ("array length %u exceeds maximum of %u at pos %d\n", -                     len, MAX_ARRAY_LENGTH, pos); -      return -1; -    } -  else -    return (int) len; -} - -static dbus_bool_t -validate_string (const DBusString *str, -                 int               pos, -                 int               len_without_nul, -                 int              *end_pos) -{ -  *end_pos = pos + len_without_nul + 1; -   -  if (*end_pos > _dbus_string_get_length (str)) -    { -      _dbus_verbose ("string length outside length of the message\n"); -      return FALSE; -    } -   -  if (_dbus_string_get_byte (str, pos + len_without_nul) != '\0') -    { -      _dbus_verbose ("string arg not nul-terminated\n"); -      return FALSE; -    } -   -  if (!_dbus_string_validate_utf8 (str, pos, len_without_nul)) -    { -      _dbus_verbose ("string is not valid UTF-8\n"); -      return FALSE; -    } - -  return TRUE; -}    - -/** - * Validates and returns a typecode at a specific position - * in the message - * - * @param str a string - * @param type the type of the argument - * @param pos the pos where the typecode starts - * @param end_pos pointer where the position right - * after the end position will follow - * @returns #TRUE if the type is valid. - */ -dbus_bool_t -_dbus_marshal_validate_type   (const DBusString *str, -			       int               pos, -			       int              *type, -			       int              *end_pos) -{ -  const char *data; -   -  if (pos >= _dbus_string_get_length (str)) -    return FALSE; - -  data = _dbus_string_get_const_data_len (str, pos, 1); - -  if (_dbus_type_is_valid (*data)) -    { -      *type = *data; -      if (end_pos != NULL) -	*end_pos = pos + 1; -      return TRUE; -    } - -  _dbus_verbose ("'%c' %d invalid type code\n", (int) *data, (int) *data); -   -  return FALSE; -} - -/* Faster validator for array data that doesn't call - * validate_arg for each value - */ -static dbus_bool_t -validate_array_data (const DBusString *str, -                     int	       byte_order, -                     int               depth, -                     int               type, -                     int               array_type_pos, -                     int               pos, -                     int              *new_pos, -                     int               end) -{ -  switch (type) -    { -    case DBUS_TYPE_INVALID: -      return FALSE; -      break; - -    case DBUS_TYPE_NIL: -      break; - -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_CUSTOM: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_DICT: -      /* This clean recursion to validate_arg is what we -       * are doing logically for all types, but we don't -       * really want to call validate_arg for every byte -       * in a byte array, so the primitive types are -       * special-cased. -       */ -      while (pos < end) -        { -          if (!_dbus_marshal_validate_arg (str, byte_order, depth, -                                           type, array_type_pos, pos, &pos)) -            return FALSE; -        } -      break; -       -    case DBUS_TYPE_BYTE: -      pos = end; -      break; -       -    case DBUS_TYPE_BOOLEAN: -      while (pos < end) -        { -          unsigned char c; -           -          c = _dbus_string_get_byte (str, pos); -           -          if (!(c == 0 || c == 1)) -            { -              _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c); -              return FALSE; -            } -           -          ++pos; -        } -      break; -       -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      /* Call validate arg one time to check alignment padding -       * at start of array -       */ -      if (!_dbus_marshal_validate_arg (str, byte_order, depth, -                                       type, array_type_pos, pos, &pos)) -        return FALSE; -      pos = _DBUS_ALIGN_VALUE (end, 4); -      break; - -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64: -    case DBUS_TYPE_DOUBLE: -      /* Call validate arg one time to check alignment padding -       * at start of array -       */ -      if (!_dbus_marshal_validate_arg (str, byte_order, depth, -                                       type, array_type_pos, pos, &pos)) -        return FALSE; -      pos = _DBUS_ALIGN_VALUE (end, 8); -      break; -       -    default: -      _dbus_verbose ("Unknown message arg type %d\n", type); -      return FALSE; -    } - -  *new_pos = pos; - -  return TRUE; -} - -/**  - * Validates an argument of a specific type, checking that it - * is well-formed, for example no ludicrous length fields, strings - * are nul-terminated, etc. - * Returns the end position of the argument in end_pos, and - * returns #TRUE if a valid arg begins at "pos" - * - * @todo security: need to audit this function. - *  - * @param str a string - * @param byte_order the byte order to use - * @param depth current recursion depth, to prevent excessive recursion - * @param type the type of the argument - * @param array_type_pos the position of the current array type, or - *        -1 if not in an array - * @param pos the pos where the arg starts - * @param end_pos pointer where the position right - * after the end position will follow - * @returns #TRUE if the arg is valid. - */ -dbus_bool_t -_dbus_marshal_validate_arg (const DBusString *str, -                            int	              byte_order, -                            int               depth, -			    int               type, -			    int               array_type_pos, -                            int               pos, -                            int              *end_pos) -{ -  if (pos > _dbus_string_get_length (str)) -    { -      _dbus_verbose ("Validation went off the end of the message\n"); -      return FALSE; -    } - -#define MAX_VALIDATION_DEPTH 32 -   -  if (depth > MAX_VALIDATION_DEPTH) -    { -      _dbus_verbose ("Maximum recursion depth reached validating message\n"); -      return FALSE; -    } -   -  switch (type) -    { -    case DBUS_TYPE_INVALID: -      return FALSE; -      break; - -    case DBUS_TYPE_NIL: -      *end_pos = pos; -      break; - -    case DBUS_TYPE_BYTE: -      if (1 > _dbus_string_get_length (str) - pos) -	{ -	  _dbus_verbose ("no room for byte value\n"); -	  return FALSE; -	} -	 -      *end_pos = pos + 1; -      break; -       -    case DBUS_TYPE_BOOLEAN: -      { -	unsigned char c; - -        if (1 > _dbus_string_get_length (str) - pos) -          { -            _dbus_verbose ("no room for boolean value\n"); -            return FALSE; -          } -         -	c = _dbus_string_get_byte (str, pos); - -	if (!(c == 0 || c == 1)) -	  { -	    _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c); -	    return FALSE; -	  } -	 -        *end_pos = pos + 1; -      } -      break; -       -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      { -        int align_4 = _DBUS_ALIGN_VALUE (pos, 4); -         -        if (!_dbus_string_validate_nul (str, pos, -                                        align_4 - pos)) -          { -            _dbus_verbose ("int32/uint32 alignment padding not initialized to nul\n"); -            return FALSE; -          } - -        *end_pos = align_4 + 4; -      } -      break; - -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:       -    case DBUS_TYPE_DOUBLE: -      { -        int align_8 = _DBUS_ALIGN_VALUE (pos, 8); - -        _dbus_verbose_bytes_of_string (str, pos, (align_8 + 8 - pos)); -         -        if (!_dbus_string_validate_nul (str, pos, -                                        align_8 - pos)) -          { -            _dbus_verbose ("double/int64/uint64/objid alignment padding not initialized to nul at %d\n", pos); -            return FALSE; -          } - -        *end_pos = align_8 + 8; -      } -      break; - -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_STRING: -      { -	int len; - -	/* Demarshal the length, which does NOT include -         * nul termination -         */ -	len = demarshal_and_validate_len (str, byte_order, pos, &pos); -        if (len < 0) -          return FALSE; - -        if (!validate_string (str, pos, len, end_pos)) -          return FALSE; - -        if (type == DBUS_TYPE_OBJECT_PATH) -          { -            if (!_dbus_string_validate_path (str, pos, len)) -              return FALSE; -          } -      } -      break; - -    case DBUS_TYPE_CUSTOM: -      { -	int len; - -	/* Demarshal the string length, which does NOT include -         * nul termination -         */ -	len = demarshal_and_validate_len (str, byte_order, pos, &pos); -        if (len < 0) -          return FALSE; - -        if (!validate_string (str, pos, len, &pos)) -          return FALSE; - -	/* Validate data */ -	len = demarshal_and_validate_len (str, byte_order, pos, &pos); -        if (len < 0) -          return FALSE; - -	*end_pos = pos + len; -      } -      break; -       -    case DBUS_TYPE_ARRAY: -      { -	int len; -	int end; -	int array_type; - -	if (array_type_pos == -1) -	  { -	    array_type_pos = pos; - -	    do -	      { -		if (!_dbus_marshal_validate_type (str, pos, &array_type, &pos)) -		  { -		    _dbus_verbose ("invalid array type\n"); -		    return FALSE; -		  } -		 -		/* NIL values take up no space, so you couldn't iterate over an array of them. -		 * array of nil seems useless anyway; the useful thing might be array of -		 * (nil OR string) but we have no framework for that. -		 */ -		if (array_type == DBUS_TYPE_NIL) -		  { -		    _dbus_verbose ("array of NIL is not allowed\n"); -		    return FALSE; -		  } -	      } -	    while (array_type == DBUS_TYPE_ARRAY); -	  } -	else -	  array_type_pos++; - -	if (!_dbus_marshal_validate_type (str, array_type_pos, &array_type, NULL)) -	  { -	    _dbus_verbose ("invalid array type\n"); -	    return FALSE; -	  } -         -	len = demarshal_and_validate_len (str, byte_order, pos, &pos); -        if (len < 0) -	  { -	    _dbus_verbose ("invalid array length (<0)\n"); -	    return FALSE; -	  } - -        if (len > _dbus_string_get_length (str) - pos) -          { -            _dbus_verbose ("array length outside length of the message\n"); -            return FALSE; -          } -	 -	end = pos + len; - -        if (len > 0 && !validate_array_data (str, byte_order, depth + 1, -					     array_type, array_type_pos, -					     pos, &pos, end)) -	  { -	    _dbus_verbose ("invalid array data\n"); -	    return FALSE; -	  } - -        if (pos < end) -          { -            /* This should not be able to happen, as long as validate_arg moves forward; -             * but the check is here just to be paranoid. -             */ -            _dbus_verbose ("array length %d specified was longer than actual array contents by %d\n", -                           len, end - pos); -            return FALSE; -          } -         -	if (pos > end) -	  { -	    _dbus_verbose ("array contents exceeds array length %d by %d\n", len, pos - end); -	    return FALSE; -	  } - -	*end_pos = pos; -      } -      break; - -    case DBUS_TYPE_DICT: -      { -	int dict_type; -	int len; -	int end; -	 -	len = demarshal_and_validate_len (str, byte_order, pos, &pos); -        if (len < 0) -          return FALSE; - -        if (len > _dbus_string_get_length (str) - pos) -          { -            _dbus_verbose ("dict length outside length of the message\n"); -            return FALSE; -          } -	 -	end = pos + len; -	 -	while (pos < end) -	  { -	    /* Validate name */ -	    if (!_dbus_marshal_validate_arg (str, byte_order, depth + 1, -					     DBUS_TYPE_STRING, -1, pos, &pos)) -	      return FALSE; -	     -	    if (!_dbus_marshal_validate_type (str, pos, &dict_type, &pos)) -	      { -		_dbus_verbose ("invalid dict entry type at offset %d\n", pos); -		return FALSE; -	      } -	     -	    /* Validate element */ -	    if (!_dbus_marshal_validate_arg (str, byte_order, depth + 1, -					     dict_type, -1, pos, &pos)) -	      { -		_dbus_verbose ("dict arg invalid at offset %d\n", pos); -		return FALSE; -	      } -	  } -	 -	if (pos > end) -	  { -	    _dbus_verbose ("dict contents exceed stated dict length\n"); -	    return FALSE; -	  } -         -	*end_pos = pos; -      } -      break; -       -    default: -      _dbus_verbose ("Unknown message arg type %d\n", type); -      return FALSE; -    } - -  if (*end_pos > _dbus_string_get_length (str)) -    return FALSE; -   -  return TRUE; -} - -/** - * Return #TRUE if the typecode is a valid typecode - * - * @returns #TRUE if valid - */ -dbus_bool_t -_dbus_type_is_valid (int typecode) -{ -  switch (typecode) -    { -    case DBUS_TYPE_NIL: -    case DBUS_TYPE_BYTE: -    case DBUS_TYPE_BOOLEAN: -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64: -    case DBUS_TYPE_DOUBLE: -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_CUSTOM: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_DICT: -    case DBUS_TYPE_OBJECT_PATH: -      return TRUE; -       -    default: -      return FALSE; -    } -} - -/** - * If in verbose mode, print a block of binary data. - * - * @todo right now it prints even if not in verbose mode - *  - * @param data the data - * @param len the length of the data - */ -void -_dbus_verbose_bytes (const unsigned char *data, -                     int                  len) -{ -  int i; -  const unsigned char *aligned; - -  _dbus_assert (len >= 0); -   -  /* Print blanks on first row if appropriate */ -  aligned = _DBUS_ALIGN_ADDRESS (data, 4); -  if (aligned > data) -    aligned -= 4; -  _dbus_assert (aligned <= data); - -  if (aligned != data) -    { -      _dbus_verbose ("%4d\t%p: ", - (data - aligned), aligned);  -      while (aligned != data) -        { -          _dbus_verbose ("    "); -          ++aligned; -        } -    } - -  /* now print the bytes */ -  i = 0; -  while (i < len) -    { -      if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) -        { -          _dbus_verbose ("%4d\t%p: ", -                   i, &data[i]); -        } -       -      if (data[i] >= 32 && -          data[i] <= 126) -        _dbus_verbose (" '%c' ", data[i]); -      else -        _dbus_verbose ("0x%s%x ", -                 data[i] <= 0xf ? "0" : "", data[i]); - -      ++i; - -      if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) -        { -          if (i > 3) -            _dbus_verbose ("BE: %d LE: %d", -                           _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]), -                           _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4])); - -          if (i > 7 &&  -              _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i]) -            { -              _dbus_verbose (" dbl: %g", -                             *(double*)&data[i-8]); -            } -           -          _dbus_verbose ("\n"); -        } -    } - -  _dbus_verbose ("\n"); -} - -/** - * Dump the given part of the string to verbose log. - * - * @param str the string - * @param start the start of range to dump - * @param len length of range - */ -void -_dbus_verbose_bytes_of_string (const DBusString    *str, -                               int                  start, -                               int                  len) -{ -  const char *d; -  int real_len; - -  real_len = _dbus_string_get_length (str); - -  _dbus_assert (start >= 0); -   -  if (start > real_len) -    { -      _dbus_verbose ("  [%d,%d) is not inside string of length %d\n", -                     start, len, real_len); -      return; -    } - -  if ((start + len) > real_len) -    { -      _dbus_verbose ("  [%d,%d) extends outside string of length %d\n", -                     start, len, real_len); -      len = real_len - start; -    } -   -  d = _dbus_string_get_const_data_len (str, start, len); - -  _dbus_verbose_bytes (d, len); -} - -/** - * Marshals a basic type - * - * @param str string to marshal to - * @param type type of value - * @param value pointer to value - * @param byte_order byte order - * @returns #TRUE on success - **/ -dbus_bool_t -_dbus_marshal_basic_type (DBusString *str, -			  char        type, -			  void       *value, -			  int         byte_order) -{ -  dbus_bool_t retval; - -  switch (type) -    { -    case DBUS_TYPE_BYTE: -    case DBUS_TYPE_BOOLEAN: -      retval = _dbus_string_append_byte (str, *(unsigned char *)value); -      break; -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      return marshal_4_octets (str, byte_order, *(dbus_uint32_t *)value); -      break; -#ifdef DBUS_HAVE_INT64 -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:  -      retval = _dbus_marshal_uint64 (str, byte_order, *(dbus_uint64_t *)value); -      break; -#endif /* DBUS_HAVE_INT64 */ -    case DBUS_TYPE_DOUBLE: -      retval = _dbus_marshal_double (str, byte_order, *(double *)value); -      break; -    default: -      _dbus_assert_not_reached ("not a basic type"); -      retval = FALSE; -      break; -    } -  return retval; -} - -/** - * Marshals a basic type array - * - * @param str string to marshal to - * @param element_type type of array elements - * @param value pointer to value - * @param len length of value data in elements - * @param byte_order byte order - * @returns #TRUE on success - **/ -dbus_bool_t -_dbus_marshal_basic_type_array (DBusString *str, -				char        element_type, -				const void *value, -				int         len, -				int         byte_order) -{ -  switch (element_type) -    { -    case DBUS_TYPE_BOOLEAN: -      /* FIXME: we canonicalize to 0 or 1 for the single boolean case  -       * should we here too ? */ -    case DBUS_TYPE_BYTE: -      return _dbus_marshal_byte_array (str, byte_order, value, len); -      break; -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -      return marshal_4_octets_array (str, byte_order, value, len); -      break; -#ifdef DBUS_HAVE_INT64 -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64:  -#endif /* DBUS_HAVE_INT64 */ -    case DBUS_TYPE_DOUBLE: -      return marshal_8_octets_array (str, byte_order, value, len); -      break; -    default: -      _dbus_assert_not_reached ("non basic type in array"); -      break; -    } -  return FALSE; -} - -/** @} */ - -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include <stdio.h> - -dbus_bool_t -_dbus_marshal_test (void) -{ -  DBusString str; -  char *tmp1, *tmp2; -  int pos = 0, len; -  dbus_int32_t array1[3] = { 0x123, 0x456, 0x789 }, *array2; -#ifdef DBUS_HAVE_INT64 -  dbus_int64_t array3[3] = { DBUS_INT64_CONSTANT (0x123ffffffff),  -                             DBUS_INT64_CONSTANT (0x456ffffffff),  -                             DBUS_INT64_CONSTANT (0x789ffffffff) }, *array4; -#endif -  char *s; -  DBusString t; -   -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("failed to init string"); - -  /* Marshal doubles */ -  if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14)) -    _dbus_assert_not_reached ("could not marshal double value"); -  if (!_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14) -    _dbus_assert_not_reached ("demarshal failed"); - -  if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14)) -    _dbus_assert_not_reached ("could not marshal double value"); -  if (!_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14) -    _dbus_assert_not_reached ("demarshal failed"); -   -  /* Marshal signed integers */ -  if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678)) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678) -    _dbus_assert_not_reached ("demarshal failed"); - -  if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678)) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678) -    _dbus_assert_not_reached ("demarshal failed"); -   -  /* Marshal unsigned integers */ -  if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678)) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678) -    _dbus_assert_not_reached ("demarshal failed"); -   -  if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678)) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678) -    _dbus_assert_not_reached ("demarshal failed"); - -#ifdef DBUS_HAVE_INT64 -  /* Marshal signed integers */ -  if (!_dbus_marshal_int64 (&str, DBUS_BIG_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7))) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (_dbus_demarshal_int64 (&str, DBUS_BIG_ENDIAN, pos, &pos) != DBUS_INT64_CONSTANT (-0x123456789abc7)) -    _dbus_assert_not_reached ("demarshal failed"); - -  if (!_dbus_marshal_int64 (&str, DBUS_LITTLE_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7))) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (_dbus_demarshal_int64 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) != DBUS_INT64_CONSTANT (-0x123456789abc7)) -    _dbus_assert_not_reached ("demarshal failed"); -   -  /* Marshal unsigned integers */ -  if (!_dbus_marshal_uint64 (&str, DBUS_BIG_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7))) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!(_dbus_demarshal_uint64 (&str, DBUS_BIG_ENDIAN, pos, &pos) == DBUS_UINT64_CONSTANT (0x123456789abc7))) -    _dbus_assert_not_reached ("demarshal failed"); -   -  if (!_dbus_marshal_uint64 (&str, DBUS_LITTLE_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7))) -    _dbus_assert_not_reached ("could not marshal signed integer value"); -  if (!(_dbus_demarshal_uint64 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == DBUS_UINT64_CONSTANT (0x123456789abc7))) -    _dbus_assert_not_reached ("demarshal failed"); -#endif /* DBUS_HAVE_INT64 */ -   -  /* Marshal strings */ -  tmp1 = "This is the dbus test string"; -  if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1)) -    _dbus_assert_not_reached ("could not marshal string"); -  tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos); -  if (!strcmp (tmp1, tmp2) == 0) -    _dbus_assert_not_reached ("demarshal failed"); -  dbus_free (tmp2); - -  tmp1 = "This is the dbus test string"; -  if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1)) -    _dbus_assert_not_reached ("could not marshal string"); -  tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos); -  if (!strcmp (tmp1, tmp2) == 0) -    _dbus_assert_not_reached ("demarshal failed"); -  dbus_free (tmp2); - -  /* Marshal signed integer arrays */ -  if (!_dbus_marshal_int32_array (&str, DBUS_BIG_ENDIAN, array1, 3)) -    _dbus_assert_not_reached ("could not marshal integer array"); -  if (!_dbus_demarshal_int32_array (&str, DBUS_BIG_ENDIAN, pos, &pos, &array2, &len)) -    _dbus_assert_not_reached ("could not demarshal integer array"); - -  if (len != 3) -    _dbus_assert_not_reached ("Signed integer array lengths differ!\n"); -  dbus_free (array2); - -#ifdef DBUS_HAVE_INT64 -  /* Marshal 64-bit signed integer arrays */ -  if (!_dbus_marshal_int64_array (&str, DBUS_BIG_ENDIAN, array3, 3)) -    _dbus_assert_not_reached ("could not marshal integer array"); -  if (!_dbus_demarshal_int64_array (&str, DBUS_BIG_ENDIAN, pos, &pos, &array4, &len)) -    _dbus_assert_not_reached ("could not demarshal integer array"); - -  if (len != 3) -    _dbus_assert_not_reached ("Signed integer array lengths differ!\n"); -  dbus_free (array4); - -  /* set/pack 64-bit integers */ -  _dbus_string_set_length (&str, 8); - -  /* signed little */ -  _dbus_marshal_set_int64 (&str, DBUS_LITTLE_ENDIAN, -                           0, DBUS_INT64_CONSTANT (-0x123456789abc7)); -   -  _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == -                _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed big */ -  _dbus_marshal_set_int64 (&str, DBUS_BIG_ENDIAN, -                           0, DBUS_INT64_CONSTANT (-0x123456789abc7)); - -  _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == -                _dbus_unpack_int64 (DBUS_BIG_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed little pack */ -  _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), -                    DBUS_LITTLE_ENDIAN, -                    _dbus_string_get_data (&str)); -   -  _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == -                _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed big pack */ -  _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), -                    DBUS_BIG_ENDIAN, -                    _dbus_string_get_data (&str)); - -  _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == -                _dbus_unpack_int64 (DBUS_BIG_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* unsigned little */ -  _dbus_marshal_set_uint64 (&str, DBUS_LITTLE_ENDIAN, -                            0, DBUS_UINT64_CONSTANT (0x123456789abc7)); -   -  _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == -                _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned big */ -  _dbus_marshal_set_uint64 (&str, DBUS_BIG_ENDIAN, -                            0, DBUS_UINT64_CONSTANT (0x123456789abc7)); - -  _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == -                _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned little pack */ -  _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), -                     DBUS_LITTLE_ENDIAN, -                     _dbus_string_get_data (&str)); -   -  _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == -                _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned big pack */ -  _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), -                     DBUS_BIG_ENDIAN, -                     _dbus_string_get_data (&str)); - -  _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == -                _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, -                                     _dbus_string_get_const_data (&str))); -   -#endif - -  /* set/pack 32-bit integers */ -  _dbus_string_set_length (&str, 4); - -  /* signed little */ -  _dbus_marshal_set_int32 (&str, DBUS_LITTLE_ENDIAN, -                           0, -0x123456); -   -  _dbus_assert (-0x123456 == -                _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed big */ -  _dbus_marshal_set_int32 (&str, DBUS_BIG_ENDIAN, -                           0, -0x123456); - -  _dbus_assert (-0x123456 == -                _dbus_unpack_int32 (DBUS_BIG_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed little pack */ -  _dbus_pack_int32 (-0x123456, -                    DBUS_LITTLE_ENDIAN, -                    _dbus_string_get_data (&str)); -   -  _dbus_assert (-0x123456 == -                _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* signed big pack */ -  _dbus_pack_int32 (-0x123456, -                    DBUS_BIG_ENDIAN, -                    _dbus_string_get_data (&str)); - -  _dbus_assert (-0x123456 == -                _dbus_unpack_int32 (DBUS_BIG_ENDIAN, -                                    _dbus_string_get_const_data (&str))); - -  /* unsigned little */ -  _dbus_marshal_set_uint32 (&str, DBUS_LITTLE_ENDIAN, -                            0, 0x123456); -   -  _dbus_assert (0x123456 == -                _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned big */ -  _dbus_marshal_set_uint32 (&str, DBUS_BIG_ENDIAN, -                            0, 0x123456); - -  _dbus_assert (0x123456 == -                _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned little pack */ -  _dbus_pack_uint32 (0x123456, -                     DBUS_LITTLE_ENDIAN, -                     _dbus_string_get_data (&str)); -   -  _dbus_assert (0x123456 == -                _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - -  /* unsigned big pack */ -  _dbus_pack_uint32 (0x123456, -                     DBUS_BIG_ENDIAN, -                     _dbus_string_get_data (&str)); - -  _dbus_assert (0x123456 == -                _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, -                                     _dbus_string_get_const_data (&str))); - - -  /* Strings */ -   -  _dbus_string_set_length (&str, 0); - -  _dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, -                        "Hello world"); -   -  s = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello world") == 0); -  dbus_free (s); - -  _dbus_string_init_const (&t, "Hello world foo"); -   -  _dbus_marshal_set_string (&str, DBUS_LITTLE_ENDIAN, 0, -                            &t, _dbus_string_get_length (&t)); -   -  s = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello world foo") == 0); -  dbus_free (s); - -  _dbus_string_init_const (&t, "Hello"); -   -  _dbus_marshal_set_string (&str, DBUS_LITTLE_ENDIAN, 0, -                            &t, _dbus_string_get_length (&t)); -   -  s = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello") == 0); -  dbus_free (s); - -  /* Strings (big endian) */ -   -  _dbus_string_set_length (&str, 0); - -  _dbus_marshal_string (&str, DBUS_BIG_ENDIAN, -                        "Hello world"); -   -  s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello world") == 0); -  dbus_free (s); - -  _dbus_string_init_const (&t, "Hello world foo"); -   -  _dbus_marshal_set_string (&str, DBUS_BIG_ENDIAN, 0, -                            &t, _dbus_string_get_length (&t)); -   -  s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello world foo") == 0); -  dbus_free (s); - -  _dbus_string_init_const (&t, "Hello"); -   -  _dbus_marshal_set_string (&str, DBUS_BIG_ENDIAN, 0, -                            &t, _dbus_string_get_length (&t)); -   -  s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL); -  _dbus_assert (strcmp (s, "Hello") == 0); -  dbus_free (s); -   -  _dbus_string_free (&str); -       -  return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal.h b/dbus/dbus-marshal.h deleted file mode 100644 index dccfc1db..00000000 --- a/dbus/dbus-marshal.h +++ /dev/null @@ -1,348 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-marshal.h  Marshalling routines - * - * Copyright (C) 2002  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 - * - */ - -#ifndef DBUS_MARSHAL_H -#define DBUS_MARSHAL_H - -#include <config.h> -#include <dbus/dbus-protocol.h> -#include <dbus/dbus-types.h> -#include <dbus/dbus-arch-deps.h> -#include <dbus/dbus-string.h> - -#ifndef PACKAGE -#error "config.h not included here" -#endif - -#ifdef WORDS_BIGENDIAN -#define DBUS_COMPILER_BYTE_ORDER DBUS_BIG_ENDIAN -#else -#define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN -#endif - -#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val)	((dbus_uint32_t) (      \ -    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) |     \ -    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) <<  8) |     \ -    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >>  8) |     \ -    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24))) - -#ifdef DBUS_HAVE_INT64 - -#define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val)	((dbus_uint64_t) (              \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000000000ff)) << 56) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000000000ff00)) << 40) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000000000ff0000)) << 24) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000ff000000)) <<  8) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000ff00000000)) >>  8) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000ff0000000000)) >> 24) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00ff000000000000)) >> 40) |    \ -      (((dbus_uint64_t) (val) &                                                 \ -	(dbus_uint64_t) DBUS_UINT64_CONSTANT (0xff00000000000000)) >> 56))) -#endif /* DBUS_HAVE_INT64 */ - -#define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) -#define DBUS_INT32_SWAP_LE_BE(val)  ((dbus_int32_t)DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) - -#ifdef DBUS_HAVE_INT64 -#define DBUS_UINT64_SWAP_LE_BE(val) (DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) -#define DBUS_INT64_SWAP_LE_BE(val)  ((dbus_int64_t)DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) -#endif /* DBUS_HAVE_INT64 */ - -#ifdef WORDS_BIGENDIAN -#define DBUS_INT32_TO_BE(val)	((dbus_int32_t) (val)) -#define DBUS_UINT32_TO_BE(val)	((dbus_uint32_t) (val)) -#define DBUS_INT32_TO_LE(val)	(DBUS_INT32_SWAP_LE_BE (val)) -#define DBUS_UINT32_TO_LE(val)	(DBUS_UINT32_SWAP_LE_BE (val)) -#  ifdef DBUS_HAVE_INT64 -#define DBUS_INT64_TO_BE(val)	((dbus_int64_t) (val)) -#define DBUS_UINT64_TO_BE(val)	((dbus_uint64_t) (val)) -#define DBUS_INT64_TO_LE(val)	(DBUS_INT64_SWAP_LE_BE (val)) -#define DBUS_UINT64_TO_LE(val)	(DBUS_UINT64_SWAP_LE_BE (val)) -#  endif /* DBUS_HAVE_INT64 */ -#else -#define DBUS_INT32_TO_LE(val)	((dbus_int32_t) (val)) -#define DBUS_UINT32_TO_LE(val)	((dbus_uint32_t) (val)) -#define DBUS_INT32_TO_BE(val)	((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val)) -#define DBUS_UINT32_TO_BE(val)	(DBUS_UINT32_SWAP_LE_BE (val)) -#  ifdef DBUS_HAVE_INT64 -#define DBUS_INT64_TO_LE(val)	((dbus_int64_t) (val)) -#define DBUS_UINT64_TO_LE(val)	((dbus_uint64_t) (val)) -#define DBUS_INT64_TO_BE(val)	((dbus_int64_t) DBUS_UINT64_SWAP_LE_BE (val)) -#define DBUS_UINT64_TO_BE(val)	(DBUS_UINT64_SWAP_LE_BE (val)) -#  endif /* DBUS_HAVE_INT64 */ -#endif - -/* The transformation is symmetric, so the FROM just maps to the TO. */ -#define DBUS_INT32_FROM_LE(val)	 (DBUS_INT32_TO_LE (val)) -#define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val)) -#define DBUS_INT32_FROM_BE(val)	 (DBUS_INT32_TO_BE (val)) -#define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val)) -#ifdef DBUS_HAVE_INT64 -#define DBUS_INT64_FROM_LE(val)	 (DBUS_INT64_TO_LE (val)) -#define DBUS_UINT64_FROM_LE(val) (DBUS_UINT64_TO_LE (val)) -#define DBUS_INT64_FROM_BE(val)	 (DBUS_INT64_TO_BE (val)) -#define DBUS_UINT64_FROM_BE(val) (DBUS_UINT64_TO_BE (val)) -#endif /* DBUS_HAVE_INT64 */ - -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); -dbus_uint32_t _dbus_unpack_uint32 (int                  byte_order, -                                   const unsigned char *data); -#ifdef DBUS_HAVE_INT64 -void          _dbus_pack_int64    (dbus_int64_t         value, -                                   int                  byte_order, -                                   unsigned char       *data); -dbus_int64_t  _dbus_unpack_int64  (int                  byte_order, -                                   const unsigned char *data); -void          _dbus_pack_uint64   (dbus_uint64_t        value, -                                   int                  byte_order, -                                   unsigned char       *data); -dbus_uint64_t _dbus_unpack_uint64 (int                  byte_order, -                                   const unsigned char *data); -#endif /* DBUS_HAVE_INT64 */ - -void        _dbus_marshal_set_int32  (DBusString       *str, -                                      int               byte_order, -                                      int               offset, -                                      dbus_int32_t      value); -void        _dbus_marshal_set_uint32 (DBusString       *str, -                                      int               byte_order, -                                      int               offset, -                                      dbus_uint32_t     value); -#ifdef DBUS_HAVE_INT64 -void        _dbus_marshal_set_int64  (DBusString       *str, -                                      int               byte_order, -                                      int               offset, -                                      dbus_int64_t      value); -void        _dbus_marshal_set_uint64 (DBusString       *str, -                                      int               byte_order, -                                      int               offset, -                                      dbus_uint64_t     value); -#endif /* DBUS_HAVE_INT64 */ - -dbus_bool_t _dbus_marshal_set_string      (DBusString         *str, -                                           int                 byte_order, -                                           int                 offset, -                                           const DBusString   *value, -                                           int                 len); -void        _dbus_marshal_set_object_path (DBusString         *str, -                                           int                 byte_order, -                                           int                 offset, -                                           const char        **path, -                                           int                 path_len); - -dbus_bool_t   _dbus_marshal_int32          (DBusString            *str, -					    int                    byte_order, -					    dbus_int32_t           value); -dbus_bool_t   _dbus_marshal_uint32         (DBusString            *str, -					    int                    byte_order, -					    dbus_uint32_t          value); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t   _dbus_marshal_int64          (DBusString            *str, -					    int                    byte_order, -					    dbus_int64_t           value); -dbus_bool_t   _dbus_marshal_uint64         (DBusString            *str, -					    int                    byte_order, -					    dbus_uint64_t          value); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t   _dbus_marshal_double         (DBusString            *str, -					    int                    byte_order, -					    double                 value); -dbus_bool_t   _dbus_marshal_string         (DBusString            *str, -					    int                    byte_order, -					    const char            *value); -dbus_bool_t   _dbus_marshal_string_len     (DBusString            *str, -					    int                    byte_order, -					    const char            *value, -                                            int                    len); -dbus_bool_t   _dbus_marshal_basic_type     (DBusString            *str, -					    char                   type, -					    void                  *value, -					    int                    byte_order); -dbus_bool_t   _dbus_marshal_byte_array     (DBusString            *str, -					    int                    byte_order, -					    const unsigned char   *value, -					    int                    len); -dbus_bool_t   _dbus_marshal_int32_array    (DBusString            *str, -					    int                    byte_order, -					    const dbus_int32_t    *value, -					    int                    len); -dbus_bool_t   _dbus_marshal_uint32_array   (DBusString            *str, -					    int                    byte_order, -					    const dbus_uint32_t   *value, -					    int                    len); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t   _dbus_marshal_int64_array    (DBusString            *str, -					    int                    byte_order, -					    const dbus_int64_t    *value, -					    int                    len); -dbus_bool_t   _dbus_marshal_uint64_array   (DBusString            *str, -					    int                    byte_order, -					    const dbus_uint64_t   *value, -					    int                    len); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t   _dbus_marshal_double_array   (DBusString            *str, -					    int                    byte_order, -					    const double          *value, -					    int                    len); -dbus_bool_t   _dbus_marshal_basic_type_array (DBusString            *str, -					      char                   element_type, -					      const void	    *value, -					      int                    len, -					      int                    byte_order); - -dbus_bool_t   _dbus_marshal_string_array   (DBusString            *str, -					    int                    byte_order, -					    const char           **value, -					    int                    len); -dbus_bool_t   _dbus_marshal_object_path    (DBusString            *str, -					    int                    byte_order, -                                            const char           **path, -                                            int                    path_len); - -double        _dbus_demarshal_double       (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -dbus_int32_t  _dbus_demarshal_int32        (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -dbus_uint32_t _dbus_demarshal_uint32       (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -#ifdef DBUS_HAVE_INT64 -dbus_int64_t  _dbus_demarshal_int64        (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -dbus_uint64_t _dbus_demarshal_uint64       (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -#endif /* DBUS_HAVE_INT64 */ -void          _dbus_demarshal_basic_type   (const DBusString      *str, -					    int                    type, -					    void                  *value, -					    int                    byte_order, -					    int                   *pos); -char *        _dbus_demarshal_string       (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos); -dbus_bool_t   _dbus_demarshal_byte_array   (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    unsigned char        **array, -					    int                   *array_len); -dbus_bool_t   _dbus_demarshal_int32_array  (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    dbus_int32_t         **array, -					    int                   *array_len); -dbus_bool_t   _dbus_demarshal_uint32_array (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    dbus_uint32_t        **array, -					    int                   *array_len); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t   _dbus_demarshal_int64_array  (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    dbus_int64_t         **array, -					    int                   *array_len); -dbus_bool_t   _dbus_demarshal_uint64_array (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    dbus_uint64_t        **array, -					    int                   *array_len); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t   _dbus_demarshal_double_array (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    double               **array, -					    int                   *array_len); -dbus_bool_t   _dbus_demarshal_basic_type_array (const DBusString      *str, -						int                    type, -						void                 **array, -						int                   *array_len, -						int                    byte_order, -						int                   *pos); - -dbus_bool_t   _dbus_demarshal_string_array (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -					    int                   *new_pos, -					    char                ***array, -					    int                   *array_len); -dbus_bool_t   _dbus_decompose_path         (const char*            data, -					    int                    len, -					    char                ***path, -					    int                   *path_len); -dbus_bool_t   _dbus_demarshal_object_path  (const DBusString      *str, -					    int                    byte_order, -					    int                    pos, -                                            int                   *new_pos, -                                            char                ***path, -                                            int                   *path_len); - -dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str, -                                           int               byte_order, -					   int               type, -                                           int               pos, -                                           int              *end_pos); -dbus_bool_t _dbus_marshal_validate_type   (const DBusString *str, -                                           int               pos, -					   int              *type, -                                           int              *end_pos); -dbus_bool_t _dbus_marshal_validate_arg    (const DBusString *str, -                                           int               depth, -                                           int               byte_order, -					   int               type, -					   int               array_type_pos, -                                           int               pos, -                                           int              *end_pos); - -dbus_bool_t _dbus_type_is_valid           (int               typecode); - -#endif /* DBUS_MARSHAL_H */ diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index 3b59c26f..b28c6b11 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -317,7 +317,8 @@ source_string (BlockSource source)  }  static void -check_guards (void *free_block) +check_guards (void       *free_block, +              dbus_bool_t overwrite)  {    if (free_block != NULL)      { @@ -364,6 +365,10 @@ check_guards (void *free_block)            i += 4;          } +      /* set memory to anything but nul bytes */ +      if (overwrite) +        memset (free_block, 'g', requested_bytes); +              if (failed)          _dbus_assert_not_reached ("guard value corruption");      } @@ -401,7 +406,7 @@ set_guards (void       *real_block,        i += 4;      } -  check_guards (block + GUARD_START_OFFSET); +  check_guards (block + GUARD_START_OFFSET, FALSE);    return block + GUARD_START_OFFSET;  } @@ -558,7 +563,7 @@ dbus_realloc (void  *memory,            size_t old_bytes;            void *block; -          check_guards (memory); +          check_guards (memory, FALSE);            block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,                             bytes + GUARD_EXTRA_SIZE); @@ -566,7 +571,7 @@ dbus_realloc (void  *memory,  	  old_bytes = *(dbus_uint32_t*)block;            if (block && bytes >= old_bytes)              /* old guards shouldn't have moved */ -            check_guards (((unsigned char*)block) + GUARD_START_OFFSET); +            check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);            return set_guards (block, bytes, SOURCE_REALLOC);          } @@ -607,7 +612,7 @@ dbus_free (void  *memory)  #ifdef DBUS_BUILD_TESTS    if (guards)      { -      check_guards (memory); +      check_guards (memory, TRUE);        if (memory)          {            n_blocks_outstanding -= 1; diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 7b2b67ef..b5b7564e 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -1051,9 +1051,10 @@ _dbus_message_data_load (DBusString       *dest,                goto parse_failed;              } -          _dbus_marshal_set_uint32 (dest, endian, size_offset, +          _dbus_marshal_set_uint32 (dest, size_offset,                                      /* subtract 1 for nul */ -                                    _dbus_string_get_length (dest) - old_len - 1); +                                    _dbus_string_get_length (dest) - old_len - 1, +                                    endian);            PERFORM_UNALIGN (dest);          } @@ -1094,9 +1095,10 @@ _dbus_message_data_load (DBusString       *dest,                goto parse_failed;              } -          _dbus_marshal_set_uint32 (dest, endian, size_offset, +          _dbus_marshal_set_uint32 (dest, size_offset,                                      /* subtract 1 for nul */ -                                    _dbus_string_get_length (dest) - old_len - 1); +                                    _dbus_string_get_length (dest) - old_len - 1, +                                    endian);            PERFORM_UNALIGN (dest);          }       diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index cd8f82ad..f03e13f6 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -38,7 +38,7 @@ void _dbus_message_get_network_data  (DBusMessage       *message,  void        _dbus_message_lock                  (DBusMessage  *message);  void        _dbus_message_unlock                (DBusMessage  *message);  void        _dbus_message_set_serial            (DBusMessage  *message, -                                                 dbus_int32_t  serial); +                                                 dbus_uint32_t serial);  dbus_bool_t _dbus_message_add_size_counter      (DBusMessage  *message,                                                   DBusCounter  *counter);  void        _dbus_message_add_size_counter_link (DBusMessage  *message, diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 143ac96a..8cb3dc64 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1,11 +1,11 @@  /* -*- mode: C; c-file-style: "gnu" -*- */  /* dbus-message.c  DBusMessage object   * - * Copyright (C) 2002, 2003, 2004  Red Hat Inc. + * 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 @@ -15,7 +15,7 @@   * 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 @@ -23,12 +23,14 @@   */  #include "dbus-internals.h" -#include "dbus-marshal.h" +#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-object-tree.h"  #include "dbus-memory.h"  #include "dbus-list.h" -#include "dbus-message-builder.h"  #include "dbus-dataslot.h"  #include <string.h> @@ -42,34 +44,24 @@   * @{   */ -/** - * Cached information about a header field in the message +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   */ -typedef struct -{ -  int name_offset;  /**< Offset to name of field */ -  int value_offset; /**< Offset to value of field */ -} HeaderField; - -/** Offset to byte order from start of header */ -#define BYTE_ORDER_OFFSET    0 -/** Offset to type from start of header */ -#define TYPE_OFFSET          1 -/** Offset to flags from start of header */ -#define FLAGS_OFFSET         2 -/** Offset to version from start of header */ -#define VERSION_OFFSET       3 -/** Offset to header length from start of header */ -#define HEADER_LENGTH_OFFSET 4 -/** Offset to body length from start of header */ -#define BODY_LENGTH_OFFSET   8 -/** Offset to client serial from start of header */ -#define CLIENT_SERIAL_OFFSET 12 +_DBUS_STRING_DEFINE_STATIC(_dbus_empty_signature_str,  ""); +#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. @@ -78,30 +70,18 @@ struct DBusMessage  {    DBusAtomic refcount; /**< Reference count */ -  DBusString header; /**< Header network data, stored -                      * separately from body so we can -                      * independently realloc it. -                      */ - -  HeaderField header_fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location -							  * of each field in "header" -							  */ +  DBusHeader header; /**< Header network data and associated cache */ -  dbus_uint32_t client_serial; /**< Cached client serial value for speed */ -  dbus_uint32_t reply_serial;  /**< Cached reply serial value for speed */ -   -  int header_padding; /**< bytes of alignment in header */ -      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; /**< Incremented when iterators are invalidated. */ +  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */    DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */ @@ -110,10 +90,12 @@ struct DBusMessage  #endif  }; +/* these have wacky values to help trap uninitialized iterators; + * but has to fit in 3 bits + */  enum { -  DBUS_MESSAGE_ITER_TYPE_MESSAGE, -  DBUS_MESSAGE_ITER_TYPE_ARRAY, -  DBUS_MESSAGE_ITER_TYPE_DICT +  DBUS_MESSAGE_ITER_TYPE_READER = 3, +  DBUS_MESSAGE_ITER_TYPE_WRITER = 7  };  /** typedef for internals of message iterator */ @@ -121,27 +103,20 @@ typedef struct DBusMessageRealIter DBusMessageRealIter;  /**   * @brief Internals of DBusMessageIter - *  + *   * Object representing a position in a message. All fields are internal.   */  struct DBusMessageRealIter  { -  DBusMessageRealIter *parent_iter; /**< parent iter, or NULL */    DBusMessage *message; /**< Message used */ -  dbus_uint32_t changed_stamp; /**< stamp to detect invalid iters */ -   -  /* This is an int instead of an enum to get a guaranteed size for the dummy: */ -  int type; /**< type of iter */ -   -  int pos; /**< Current position in the string */ -  int end; /**< position right after the container */ -  int container_start; /**< offset of the start of the container */ -  int container_length_pos; /**< offset of the length of the container */ -   -  int wrote_dict_key; /**< whether we wrote the dict key for the current dict element */ - -  int array_type_pos; /**< pointer to the position of the array element type */ -  int array_type_done; /**< TRUE if the array type is fully finished */ +  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< stamp to detect invalid iters */ +  dbus_uint32_t iter_type : 3;      /**< whether this is a reader or writer iter */ +  dbus_uint32_t sig_refcount : 8;   /**< depth of open_signature() */ +  union +  { +    DBusTypeWriter writer; +    DBusTypeReader reader; +  } u;  };  /** @@ -160,823 +135,27 @@ _dbus_message_get_network_data (DBusMessage          *message,                                  const DBusString    **body)  {    _dbus_assert (message->locked); -   -  *header = &message->header; -  *body = &message->body; -} - -static void -clear_header_padding (DBusMessage *message) -{ -  _dbus_string_shorten (&message->header, -                        message->header_padding); -  message->header_padding = 0; -}               - -#ifdef DBUS_DISABLE_CHECKS -#define is_valid_error_name(x) TRUE -#else -static dbus_bool_t -is_valid_error_name (const char *error_name)                                           -{ -  DBusString the_error_name; - -  if (error_name == NULL) -    return FALSE; -   -  _dbus_string_init_const (&the_error_name, error_name); -  return _dbus_string_validate_error_name (&the_error_name, 0,    -                                           _dbus_string_get_length (&the_error_name)); -} -#endif - -static dbus_bool_t -append_header_padding (DBusMessage *message) -{ -  int old_len; -  old_len = _dbus_string_get_length (&message->header); -  if (!_dbus_string_align_length (&message->header, 8)) -    return FALSE; - -  message->header_padding = _dbus_string_get_length (&message->header) - old_len; - -  return TRUE; -} - -#ifdef DBUS_BUILD_TESTS -/* tests-only until it's actually used */ -static dbus_int32_t -get_int_field (DBusMessage *message, -               int          field) -{ -  int offset; - -  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); -   -  offset = message->header_fields[field].value_offset; -   -  if (offset < 0) -    return -1; /* useless if -1 is a valid value of course */ -   -  return _dbus_demarshal_int32 (&message->header, -                                message->byte_order, -                                offset, -                                NULL); -} -#endif - -static dbus_uint32_t -get_uint_field (DBusMessage *message, -                int          field) -{ -  int offset; -   -  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); -   -  offset = message->header_fields[field].value_offset; -   -  if (offset < 0) -    return 0; /* useless if 0 is a valid value of course */ -   -  return _dbus_demarshal_uint32 (&message->header, -                                 message->byte_order, -                                 offset, -                                 NULL); -} - -static const char* -get_string_field (DBusMessage *message, -                  int          field, -                  int         *len) -{ -  int offset; -  const char *data; - -  _dbus_return_val_if_fail (message->generation == _dbus_current_generation, -                            NULL); -   -  offset = message->header_fields[field].value_offset; - -  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); -   -  if (offset < 0) -    return NULL; - -  /* offset points to string length, string data follows it */ -  /* FIXME _dbus_demarshal_const_string() that returned -   * a reference to the string plus its len might be nice. -   */ -   -  if (len) -    *len = _dbus_demarshal_uint32 (&message->header, -                                   message->byte_order, -                                   offset, -                                   NULL); - -  data = _dbus_string_get_const_data (&message->header); -   -  return data + (offset + 4);  -} - -/* returns FALSE if no memory, TRUE with NULL path if no field */ -static dbus_bool_t -get_path_field_decomposed (DBusMessage  *message, -                           int           field, -                           char       ***path) -{ -  int offset; - -  offset = message->header_fields[field].value_offset; - -  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); -   -  if (offset < 0) -    { -      *path = NULL; -      return TRUE; -    } - -  return _dbus_demarshal_object_path (&message->header, -                                      message->byte_order, -                                      offset, -                                      NULL, -                                      path, NULL); -} - -#ifdef DBUS_BUILD_TESTS -static dbus_bool_t -append_int_field (DBusMessage *message, -                  int          field, -                  int          value) -{ -  _dbus_assert (!message->locked); - -  clear_header_padding (message); -   -  message->header_fields[field].name_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_string_append_byte (&message->header, field)) -    goto failed; - -  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32)) -    goto failed; - -  if (!_dbus_string_align_length (&message->header, 4)) -    goto failed; -   -  message->header_fields[field].value_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_marshal_int32 (&message->header, message->byte_order, -                            value)) -    goto failed; - -  if (!append_header_padding (message)) -    goto failed; -   -  return TRUE; -   - failed: -  _dbus_string_set_length (&message->header, -			   message->header_fields[field].name_offset); -  message->header_fields[field].name_offset  = -1; -  message->header_fields[field].value_offset = -1; - -  /* this must succeed because it was allocated on function entry and -   * DBusString doesn't ever realloc smaller -   */ -  if (!append_header_padding (message)) -    _dbus_assert_not_reached ("failed to reappend header padding"); -  return FALSE; -} -#endif - -static dbus_bool_t -append_uint_field (DBusMessage *message, -                   int          field, -		   int          value) -{ -  _dbus_assert (!message->locked); - -  clear_header_padding (message); -   -  message->header_fields[field].name_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_string_append_byte (&message->header, field)) -    goto failed; - -  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32)) -    goto failed; - -  if (!_dbus_string_align_length (&message->header, 4)) -    goto failed; -   -  message->header_fields[field].value_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, -                             value)) -    goto failed; - -  if (!append_header_padding (message)) -    goto failed; -   -  return TRUE; -   - failed: -  _dbus_string_set_length (&message->header, -			   message->header_fields[field].name_offset); -  message->header_fields[field].name_offset  = -1; -  message->header_fields[field].value_offset = -1; - -  /* this must succeed because it was allocated on function entry and -   * DBusString doesn't ever realloc smaller -   */ -  if (!append_header_padding (message)) -    _dbus_assert_not_reached ("failed to reappend header padding"); -  return FALSE; -} - -/** The maximum number of bytes of overhead to append to a string - * (fieldcode + typecode + alignment + length + nul + headerpadding) - */ -#define MAX_BYTES_OVERHEAD_TO_APPEND_A_STRING (1 + 1 + 3 + 4 + 1 + 8) - -static dbus_bool_t -append_string_field_len (DBusMessage *message, -                         int          field, -                         int          type, -                         const char  *value, -                         int          value_len) -{ -  _dbus_assert (!message->locked); - -  clear_header_padding (message); -   -  message->header_fields[field].name_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_string_append_byte (&message->header, field)) -    goto failed; -   -  if (!_dbus_string_append_byte (&message->header, type)) -    goto failed; - -  if (!_dbus_string_align_length (&message->header, 4)) -    goto failed; -   -  message->header_fields[field].value_offset = -    _dbus_string_get_length (&message->header); -   -  if (!_dbus_marshal_string_len (&message->header, message->byte_order, -                                 value, value_len)) -    goto failed; - -  if (!append_header_padding (message)) -    goto failed; -   -  return TRUE; -   - failed: -  _dbus_string_set_length (&message->header, -			   message->header_fields[field].name_offset); -  message->header_fields[field].name_offset  = -1; -  message->header_fields[field].value_offset = -1; - -  /* this must succeed because it was allocated on function entry and -   * DBusString doesn't ever realloc smaller -   */ -  if (!append_header_padding (message)) -    _dbus_assert_not_reached ("failed to reappend header padding"); -   -  return FALSE; -} - -static dbus_bool_t -append_string_field (DBusMessage *message, -                     int          field, -                     int          type, -                     const char  *value) -{ -  int value_len; - -  value_len = strlen (value); - -  return append_string_field_len (message, field, type, value, value_len); -} - -static int -get_type_alignment (int type) -{ -  int alignment; -   -  switch (type) -    { -    case DBUS_TYPE_NIL: -    case DBUS_TYPE_BYTE: -    case DBUS_TYPE_BOOLEAN: -      alignment = 0; -      break; - -    case DBUS_TYPE_INT32: -    case DBUS_TYPE_UINT32: -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_OBJECT_PATH: -      /* These are aligned 4 because they have a length as the -       * first field; -       */ -    case DBUS_TYPE_CUSTOM: -    case DBUS_TYPE_DICT: -      alignment = 4; -      break; - -    case DBUS_TYPE_INT64: -    case DBUS_TYPE_UINT64: -    case DBUS_TYPE_DOUBLE: -      alignment = 8; -      break; - -    case DBUS_TYPE_ARRAY: -      _dbus_assert_not_reached ("passed an ARRAY type to get_type_alignment()"); -      alignment = 0; /* quiet gcc */ -      break; - -    case DBUS_TYPE_INVALID: -    default: -      _dbus_assert_not_reached ("passed an invalid or unknown type to get_type_alignment()"); -      alignment = 0; /* quiet gcc */ -      break; -    } - -  return alignment; -} - -static dbus_bool_t -iterate_one_field (const DBusString *str, -                   int               byte_order, -                   int               name_offset, -                   int              *next_offset_p, -                   int              *field_name_p, -                   DBusString       *append_copy_to, -                   int              *copy_name_offset_p, -                   int              *copy_value_offset_p) -{ -  int name, type, array_type; -  int alignment; -  int type_len; -  int type_pos; -  int value_pos; -  int value_len; -  int value_end; -  int pos; - -#if 0 -  _dbus_verbose ("%s: name_offset=%d, append to %p\n", -                 _DBUS_FUNCTION_NAME, name_offset, append_copy_to); -#endif -   -  pos = name_offset; -   -  name = _dbus_string_get_byte (str, name_offset); -  pos++; - -  type_pos = pos; -  type = _dbus_string_get_byte (str, type_pos); -  pos++; -  type_len = 1; - -  array_type = type; -  /* find out the type of our array */ -  while (array_type == DBUS_TYPE_ARRAY) -    { -      pos++; -      type_len++; -      array_type = _dbus_string_get_byte (str, pos); -    } -#if 0 -  _dbus_verbose ("%s: name %s, type '%c' %d at %d len %d, array type '%c' %d\n", -                 _DBUS_FUNCTION_NAME, -                 _dbus_header_field_to_string (name), -                 type, type, type_pos, type_len, array_type, array_type); -#endif -   -#ifndef DBUS_DISABLE_ASSERT -  if (!_dbus_type_is_valid (array_type)) -    { -      _dbus_warn ("type '%c' %d is not valid in %s\n", -                  array_type, array_type, _DBUS_FUNCTION_NAME); -      _dbus_assert_not_reached ("invalid type"); -    } -#endif -       -  alignment = get_type_alignment (array_type); -       -  if (alignment > 0) -    pos = _DBUS_ALIGN_VALUE (pos, alignment); - -  _dbus_verbose ("%s: alignment %d value at pos %d\n", -                 _DBUS_FUNCTION_NAME, alignment, pos); -   -  /* pos now points to our value */ -  if (!_dbus_marshal_get_arg_end_pos (str, byte_order, -                                      type, pos, &value_end)) -    _dbus_assert_not_reached ("failed to get the byte after this header"); - -  value_pos = pos; -  value_len = value_end - value_pos; - -  _dbus_verbose ("%s: value_pos %d value_len %d value_end %d\n", -                 _DBUS_FUNCTION_NAME, value_pos, value_len, value_end); -   -  if (next_offset_p) -    *next_offset_p = pos + value_len; - -  if (field_name_p) -    *field_name_p = name; - -  if (append_copy_to) -    { -      int orig_len; - -      orig_len = _dbus_string_get_length (append_copy_to); - -      if (copy_name_offset_p) -        *copy_name_offset_p = orig_len; -       -      if (!_dbus_string_append_byte (append_copy_to, name)) -        goto failed_copy; - -      if (!_dbus_string_copy_len (str, type_pos, type_len, -                                  append_copy_to, -                                  _dbus_string_get_length (append_copy_to))) -        goto failed_copy; - -      if (!_dbus_string_align_length (append_copy_to, alignment)) -        goto failed_copy; - -      if (copy_value_offset_p) -        *copy_value_offset_p = _dbus_string_get_length (append_copy_to); -       -      if (!_dbus_string_copy_len (str, value_pos, value_len, -                                  append_copy_to, -                                  _dbus_string_get_length (append_copy_to))) -        goto failed_copy; -       -      return TRUE; - -    failed_copy: -      _dbus_verbose ("%s: Failed copying old fields to new string\n", -                     _DBUS_FUNCTION_NAME); -      _dbus_string_set_length (append_copy_to, orig_len); -      return FALSE; -    } -  else -    return TRUE; -} - -#ifndef DBUS_DISABLE_ASSERT -static void -verify_header_fields (DBusMessage *message) -{ -  int i; -  i = 0; -  while (i <= DBUS_HEADER_FIELD_LAST) -    { -      if (message->header_fields[i].name_offset >= 0) -        _dbus_assert (_dbus_string_get_byte (&message->header, -                                             message->header_fields[i].name_offset) == -                      i); -      ++i; -    } -} -#else /* DBUS_DISABLE_ASSERT */ -#define verify_header_fields(x) -#endif /* DBUS_DISABLE_ASSERT */ - -/* In this function we delete one field and re-align all the fields - * following it. - */ -static dbus_bool_t -delete_one_and_re_align (DBusMessage *message, -                         int          name_offset_to_delete) -{ -  DBusString copy; -  int new_fields_front_padding; -  int next_offset; -  int field_name; -  dbus_bool_t retval; -  HeaderField new_header_fields[DBUS_HEADER_FIELD_LAST+1]; -   -  _dbus_assert (name_offset_to_delete < _dbus_string_get_length (&message->header)); -  verify_header_fields (message); - -  _dbus_verbose ("%s: Deleting one field at offset %d\n", -                 _DBUS_FUNCTION_NAME, -                 name_offset_to_delete); -   -  retval = FALSE; - -  clear_header_padding (message); -   -  if (!_dbus_string_init_preallocated (©, -                                       _dbus_string_get_length (&message->header) - -                                       name_offset_to_delete + 8)) -    { -      _dbus_verbose ("%s: Failed to init string to hold copy of fields\n", -                     _DBUS_FUNCTION_NAME); -      goto out_0; -    } -   -  /* Align the name offset of the first field in the same way it's -   * aligned in the real header -   */ -  new_fields_front_padding = name_offset_to_delete % 8; - -  if (!_dbus_string_insert_bytes (©, 0, new_fields_front_padding, -                                  '\0')) -    _dbus_assert_not_reached ("Should not have failed to insert bytes into preallocated string\n"); - -  memcpy (new_header_fields, message->header_fields, -          sizeof (new_header_fields)); -   -  /* Now just re-marshal each field in the header to our temporary -   * buffer, skipping the first one. The tricky part is that the -   * fields are padded as if for previous_name_offset, but are in fact -   * at unaligned_name_offset -   */ - -  if (!iterate_one_field (&message->header, -                          message->byte_order, -                          name_offset_to_delete, -                          &next_offset, -                          &field_name, NULL, NULL, NULL)) -    _dbus_assert_not_reached ("shouldn't have failed to alloc memory to skip the deleted field"); - -  _dbus_verbose ("  Skipping %s field which will be deleted; next_offset = %d\n", -                 _dbus_header_field_to_string (field_name), next_offset); -   -  /* This field no longer exists */ -  if (field_name <= DBUS_HEADER_FIELD_LAST) -    { -      new_header_fields[field_name].name_offset = -1; -      new_header_fields[field_name].value_offset = -1; -    } -   -  while (next_offset < _dbus_string_get_length (&message->header)) -    { -      int copy_name_offset; -      int copy_value_offset; - -      if (!iterate_one_field (&message->header, -                              message->byte_order, -                              next_offset, -                              &next_offset, -                              &field_name, -                              ©, -                              ©_name_offset, -                              ©_value_offset)) -        { -          _dbus_verbose ("%s: OOM iterating one field\n", -                         _DBUS_FUNCTION_NAME); -          goto out_1; -        } -       -      if (field_name <= DBUS_HEADER_FIELD_LAST) -        { -          new_header_fields[field_name].name_offset = copy_name_offset - new_fields_front_padding + name_offset_to_delete; -          new_header_fields[field_name].value_offset = copy_value_offset - new_fields_front_padding + name_offset_to_delete; -           -          _dbus_verbose ("  Re-adding %s field at name_offset = %d value_offset = %d; next_offset = %d\n", -                         _dbus_header_field_to_string (field_name), -                         new_header_fields[field_name].name_offset, -                         new_header_fields[field_name].value_offset, -                         next_offset); -        } -    } - -  if (!_dbus_string_replace_len (©, -                                 new_fields_front_padding, -                                 _dbus_string_get_length (©) - new_fields_front_padding, -                                 &message->header, -                                 name_offset_to_delete, -                                 _dbus_string_get_length (&message->header) - name_offset_to_delete)) -    { -      _dbus_verbose ("%s: OOM moving copy back into header\n", -                     _DBUS_FUNCTION_NAME); -      goto out_1; -    } -   -  memcpy (message->header_fields, new_header_fields, -          sizeof (new_header_fields)); -  verify_header_fields (message); -   -  retval = TRUE; -   - out_1: -  _dbus_string_free (©); -   - out_0: -  if (!append_header_padding (message)) -    _dbus_assert_not_reached ("Failed to re-append header padding in re_align_field_recurse()"); -   -  return retval; -} - -static dbus_bool_t -delete_field (DBusMessage *message, -	      int          field, -              int          prealloc_header_space) -{ -  int offset; - -  _dbus_assert (!message->locked); - -  /* Prealloc */ -  if (!_dbus_string_lengthen (&message->header, prealloc_header_space)) -    { -      _dbus_verbose ("failed to prealloc %d bytes header space\n", -                     prealloc_header_space); -      return FALSE; -    } -  _dbus_string_shorten (&message->header, prealloc_header_space); - -  /* Delete */ -  offset = message->header_fields[field].name_offset; -  if (offset < 0) -    { -      _dbus_verbose ("header field didn't exist, no need to delete\n"); -      return TRUE; /* field didn't exist */ -    } - -  return delete_one_and_re_align (message, offset); -} - -#ifdef DBUS_BUILD_TESTS -static dbus_bool_t -set_int_field (DBusMessage *message, -               int          field, -               int          value) -{ -  int offset = message->header_fields[field].value_offset; - -  _dbus_assert (!message->locked); - -  _dbus_verbose ("set_int_field() field %d value '%d'\n", -                 field, value); -   -  if (offset < 0) -    { -      /* need to append the field */ -      return append_int_field (message, field, value); -    } -  else -    { -      _dbus_marshal_set_int32 (&message->header, -                               message->byte_order, -                               offset, value); - -      return TRUE; -    } -} -#endif - -static dbus_bool_t -set_uint_field (DBusMessage  *message, -                int           field, -                dbus_uint32_t value) -{ -  int offset = message->header_fields[field].value_offset; - -  _dbus_assert (!message->locked); - -  _dbus_verbose ("set_uint_field() field %d value '%u'\n", -                 field, value); -   -  if (offset < 0) -    { -      /* need to append the field */ -      return append_uint_field (message, field, value); -    } -  else -    { -      _dbus_marshal_set_uint32 (&message->header, -                                message->byte_order, -                                offset, value); - -      return TRUE; -    } -} - -static dbus_bool_t -set_string_field (DBusMessage *message, -                  int          field, -                  int          type, -                  const char  *value) -{ -  int prealloc; -  int value_len; -   -  _dbus_assert (!message->locked); - -  value_len = value ? strlen (value) : 0; -   -  /* the prealloc is so the append_string_field() -   * below won't fail, leaving us in inconsistent state -   */ -  prealloc = value_len + MAX_BYTES_OVERHEAD_TO_APPEND_A_STRING; - -  _dbus_verbose ("set_string_field() field %d prealloc %d value '%s'\n", -                 field, prealloc, value); -   -  if (!delete_field (message, field, prealloc)) -    return FALSE; - -  if (value != NULL) -    { -      /* need to append the field */ -      if (!append_string_field_len (message, field, type, value, value_len)) -        _dbus_assert_not_reached ("Appending string field shouldn't have failed, due to preallocation"); -    } -   -  return TRUE; +  *header = &message->header.data; +  *body = &message->body;  }  /** - * Sets the serial number of a message.  + * Sets the serial number of a message.   * This can only be done once on a message. - *  + *   * @param message the message   * @param serial the serial   */  void -_dbus_message_set_serial (DBusMessage  *message, -                          dbus_int32_t  serial) -{ -  _dbus_assert (!message->locked); -  _dbus_assert (dbus_message_get_serial (message) == 0); - -  _dbus_marshal_set_uint32 (&message->header, -                            message->byte_order, -                            CLIENT_SERIAL_OFFSET, -			    serial); - -  message->client_serial = serial; -} - -/** - * Sets the reply serial of a message (the client serial - * of the message this is a reply to). - * - * @param message the message - * @param reply_serial the client serial - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_reply_serial (DBusMessage   *message, -                               dbus_uint32_t  reply_serial) -{ -  _dbus_assert (!message->locked); - -  if (set_uint_field (message, -		      DBUS_HEADER_FIELD_REPLY_SERIAL, -                      reply_serial)) -    { -      message->reply_serial = reply_serial; -      return TRUE; -    } -  else -    return FALSE; -} - -/** - * Returns the serial of a message or 0 if none has been specified. - * The message's serial number is provided by the application sending - * the message and is used to identify replies to this message.  All - * messages received on a connection will have a serial, but messages - * you haven't sent yet may return 0. - * - * @param message the message - * @returns the client serial - */ -dbus_uint32_t -dbus_message_get_serial (DBusMessage *message) +_dbus_message_set_serial (DBusMessage   *message, +                          dbus_uint32_t  serial)  { -  return message->client_serial; -} +  _dbus_return_if_fail (message != NULL); +  _dbus_return_if_fail (!message->locked); +  _dbus_return_if_fail (dbus_message_get_serial (message) == 0); -/** - * Returns the serial that the message is a reply to or 0 if none. - * - * @param message the message - * @returns the reply serial - */ -dbus_uint32_t -dbus_message_get_reply_serial  (DBusMessage *message) -{ -  return message->reply_serial; +  _dbus_header_set_serial (&message->header, serial);  }  /** @@ -1004,17 +183,17 @@ _dbus_message_add_size_counter_link (DBusMessage  *message,    if (message->size_counters == NULL)      {        message->size_counter_delta = -        _dbus_string_get_length (&message->header) + +        _dbus_string_get_length (&message->header.data) +          _dbus_string_get_length (&message->body); -       +  #if 0        _dbus_verbose ("message has size %ld\n",                       message->size_counter_delta);  #endif      } -   +    _dbus_list_append_link (&message->size_counters, link); -   +    _dbus_counter_adjust (link->data, message->size_counter_delta);  } @@ -1074,106 +253,6 @@ _dbus_message_remove_size_counter (DBusMessage  *message,    _dbus_counter_unref (counter);  } -static dbus_bool_t -dbus_message_create_header (DBusMessage *message, -                            int          type, -                            const char  *service, -                            const char  *path, -                            const char  *interface, -                            const char  *member, -                            const char  *error_name) -{ -  unsigned int flags; - -  _dbus_assert ((interface && member) || -                (error_name) || -                !(interface || member || error_name)); -  _dbus_assert (error_name == NULL || is_valid_error_name (error_name)); -   -  if (!_dbus_string_append_byte (&message->header, message->byte_order)) -    return FALSE; - -  if (!_dbus_string_append_byte (&message->header, type)) -    return FALSE; -   -  flags = 0; -  if (!_dbus_string_append_byte (&message->header, flags)) -    return FALSE; - -  if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION)) -    return FALSE; - -  /* header length */ -  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) -    return FALSE; - -  /* body length */ -  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) -    return FALSE; - -  /* serial */ -  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) -    return FALSE; -   -  /* Marshal all the fields (Marshall Fields?) */ -   -  if (path != NULL) -    { -      if (!append_string_field (message, -                                DBUS_HEADER_FIELD_PATH, -				DBUS_TYPE_OBJECT_PATH, -                                path)) -        return FALSE; -    } -   -  if (service != NULL) -    { -      if (!append_string_field (message, -                                DBUS_HEADER_FIELD_DESTINATION, -				DBUS_TYPE_STRING, -                                service)) -        return FALSE; -    } - -  if (interface != NULL) -    { -      if (!append_string_field (message, -                                DBUS_HEADER_FIELD_INTERFACE, -				DBUS_TYPE_STRING, -                                interface)) -        return FALSE; -    } - -  if (member != NULL) -    { -      if (!append_string_field (message, -                                DBUS_HEADER_FIELD_MEMBER, -				DBUS_TYPE_STRING, -                                member)) -        return FALSE; -    } - -  if (error_name != NULL) -    { -      if (!append_string_field (message, -                                DBUS_HEADER_FIELD_ERROR_NAME, -				DBUS_TYPE_STRING, -                                error_name)) -        return FALSE; -    } - -  /* @todo if we make signature optional when body is empty, we don't -   * need to do this here. -   */ -  if (!append_string_field (message, -                            DBUS_HEADER_FIELD_SIGNATURE, -                            DBUS_TYPE_STRING, -                            "")) -    return FALSE; -   -  return TRUE; -} -  /**   * Locks a message. Allows checking that applications don't keep a   * reference to a message in the outgoing queue and change it @@ -1188,36 +267,53 @@ _dbus_message_lock (DBusMessage  *message)  {    if (!message->locked)      { -      /* Fill in our lengths */ -      _dbus_marshal_set_uint32 (&message->header, -				message->byte_order, -				HEADER_LENGTH_OFFSET, -				_dbus_string_get_length (&message->header)); +      _dbus_header_update_lengths (&message->header, +                                   _dbus_string_get_length (&message->body)); -      _dbus_marshal_set_uint32 (&message->header, -				message->byte_order, -				BODY_LENGTH_OFFSET, -				_dbus_string_get_length (&message->body)); +      /* must have a signature if you have a body */ +      _dbus_assert (_dbus_string_get_length (&message->body) == 0 || +                    dbus_message_get_signature (message) != NULL);        message->locked = TRUE;      }  } -/** @} */ +static dbus_bool_t +set_or_delete_string_field (DBusMessage *message, +                            int          field, +                            int          typecode, +                            const char  *value) +{ +  if (value == NULL) +    return _dbus_header_delete_field (&message->header, field); +  else +    return _dbus_header_set_field_basic (&message->header, +                                         field, +                                         typecode, +                                         &value); +} -/** - * @defgroup DBusMessage DBusMessage - * @ingroup  DBus - * @brief Message to be sent or received over a DBusConnection. - * - * A DBusMessage is the most basic unit of communication over a - * DBusConnection. A DBusConnection represents a stream of messages - * received from a remote application, and a stream of messages - * sent to a remote application. - * - * @{ - */ +static void +get_const_signature (DBusHeader        *header, +                     const DBusString **type_str_p, +                     int               *type_pos_p) +{ +  if (_dbus_header_get_field_raw (header, +                                  DBUS_HEADER_FIELD_SIGNATURE, +                                  type_str_p, +                                  type_pos_p)) +    { +      *type_pos_p += 1; /* skip the signature length which is 1 byte */ +    } +  else +    { +      *type_str_p = &_dbus_empty_signature_str; +      *type_pos_p = 0; +    } +} +#if 0 +/* Probably we don't need to use this */  /**   * Sets the signature of the message, i.e. the arguments in the   * message payload. The signature includes only "in" arguments for @@ -1226,147 +322,130 @@ _dbus_message_lock (DBusMessage  *message)   * what you might expect (it does not include the signature of the   * entire C++-style method).   * - * The signature is a string made up of type codes such - * as #DBUS_TYPE_STRING. The string is terminated with nul - * (nul is also the value of #DBUS_TYPE_INVALID). - *  + * The signature is a string made up of type codes such as + * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also + * the value of #DBUS_TYPE_INVALID). The macros such as + * #DBUS_TYPE_INT32 evaluate to integers; to assemble a signature you + * may find it useful to use the string forms, such as + * #DBUS_TYPE_INT32_AS_STRING. + * + * An "unset" or #NULL signature is considered the same as an empty + * signature. In fact dbus_message_get_signature() will never return + * #NULL. + *   * @param message the message   * @param signature the type signature or #NULL to unset   * @returns #FALSE if no memory   */  static dbus_bool_t -dbus_message_set_signature (DBusMessage *message, -                            const char  *signature) +_dbus_message_set_signature (DBusMessage *message, +                             const char  *signature)  {    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (!message->locked, FALSE); -   -  return set_string_field (message, -                           DBUS_HEADER_FIELD_SIGNATURE, -                           DBUS_TYPE_STRING, -                           signature); +  _dbus_return_val_if_fail (signature == NULL || +                            _dbus_check_is_valid_signature (signature)); +  /* can't delete the signature if you have a message body */ +  _dbus_return_val_if_fail (_dbus_string_get_length (&message->body) == 0 || +                            signature != NULL); + +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_SIGNATURE, +                                     DBUS_TYPE_SIGNATURE, +                                     signature);  } +#endif + +/** @} */  /** - * Appends to the signature of the message. - * (currently a static function, maybe should be public?) - *  - * @param message the message - * @param append_bytes nul-terminated bytes to append to the type signature - * @returns #FALSE if no memory + * @defgroup DBusMessage DBusMessage + * @ingroup  DBus + * @brief Message to be sent or received over a DBusConnection. + * + * A DBusMessage is the most basic unit of communication over a + * DBusConnection. A DBusConnection represents a stream of messages + * received from a remote application, and a stream of messages + * sent to a remote application. + * + * @{   */ -static dbus_bool_t -dbus_message_append_to_signature (DBusMessage *message, -                                  const char  *append_bytes) -{ -  const char *signature; -  DBusString append_str; -  dbus_bool_t retval; -   -  _dbus_return_val_if_fail (append_bytes != NULL, FALSE); -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); -  retval = FALSE; -   -  /* FIXME Just really inefficient for the moment; later we could -   * speed it up a lot by poking more directly at the header data -   */ -  signature = dbus_message_get_signature (message); - -  if (!_dbus_string_init (&append_str)) -    return FALSE; - -  if (signature && !_dbus_string_append (&append_str, signature)) -    goto out; - -  if (!_dbus_string_append (&append_str, append_bytes)) -    goto out; -   -  if (!set_string_field (message, -                         DBUS_HEADER_FIELD_SIGNATURE, -                         DBUS_TYPE_STRING, -                         _dbus_string_get_const_data (&append_str))) -    goto out; +/** + * @typedef DBusMessage + * + * Opaque data type representing a message received from or to be + * sent to another application. + */ -  retval = TRUE; -   - out: -   -  _dbus_string_free (&append_str); +/** + * Returns the serial of a message or 0 if none has been specified. + * The message's serial number is provided by the application sending + * the message and is used to identify replies to this message.  All + * messages received on a connection will have a serial, but messages + * you haven't sent yet may return 0. + * + * @param message the message + * @returns the client serial + */ +dbus_uint32_t +dbus_message_get_serial (DBusMessage *message) +{ +  _dbus_return_val_if_fail (message != NULL, 0); -  return retval; +  return _dbus_header_get_serial (&message->header);  }  /** - * Appends one byte to the signature of the message. - * Internal function. - *  + * Sets the reply serial of a message (the client serial + * of the message this is a reply to). + *   * @param message the message - * @param append_byte the byte  - * @returns #FALSE if no memory + * @param reply_serial the client serial + * @returns #FALSE if not enough memory   */ -static dbus_bool_t -_dbus_message_append_byte_to_signature (DBusMessage  *message, -                                        unsigned char append_byte) +dbus_bool_t +dbus_message_set_reply_serial (DBusMessage   *message, +                               dbus_uint32_t  reply_serial)  { -  char buf[2]; -      _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (!message->locked, FALSE); -   -  buf[0] = append_byte; -  buf[1] = '\0'; -  return dbus_message_append_to_signature (message, buf); +  return _dbus_header_set_field_basic (&message->header, +                                       DBUS_HEADER_FIELD_REPLY_SERIAL, +                                       DBUS_TYPE_UINT32, +                                       &reply_serial);  }  /** - * Removes the last byte from the signature of the message. - * Internal function. - *  + * Returns the serial that the message is a reply to or 0 if none. + *   * @param message the message + * @returns the reply serial   */ -static void -_dbus_message_remove_byte_from_signature (DBusMessage  *message) +dbus_uint32_t +dbus_message_get_reply_serial  (DBusMessage *message)  { -  const char *signature; -   -  _dbus_return_if_fail (message != NULL); -  _dbus_return_if_fail (!message->locked); - -  signature = dbus_message_get_signature (message); +  dbus_uint32_t v_UINT32; -  _dbus_return_if_fail (signature != NULL); -   -  if (!delete_field (message, -                     DBUS_HEADER_FIELD_SIGNATURE, -                     0)) -    _dbus_assert_not_reached ("failed to delete signature field"); +  _dbus_return_val_if_fail (message != NULL, 0); -  /* reappend one shorter (could this be any less efficient? the code will -   * go away later anyhow) -   */ -  if (!append_string_field_len (message, DBUS_HEADER_FIELD_SIGNATURE, -                                DBUS_TYPE_STRING, signature, -                                strlen (signature) - 1)) -    _dbus_assert_not_reached ("reappending shorter signature shouldn't have failed"); +  if (_dbus_header_get_field_basic (&message->header, +                                    DBUS_HEADER_FIELD_REPLY_SERIAL, +                                    DBUS_TYPE_UINT32, +                                    &v_UINT32)) +    return v_UINT32; +  else +    return 0;  } -/** - * @typedef DBusMessage - * - * Opaque data type representing a message received from or to be - * sent to another application. - */ -  static void  free_size_counter (void *element,                     void *data)  {    DBusCounter *counter = element;    DBusMessage *message = data; -   +    _dbus_counter_adjust (counter, - message->size_counter_delta);    _dbus_counter_unref (counter); @@ -1376,22 +455,22 @@ static void  dbus_message_finalize (DBusMessage *message)  {    _dbus_assert (message->refcount.value == 0); -   +    /* This calls application callbacks! */    _dbus_data_slot_list_free (&message->slot_list); -   +    _dbus_list_foreach (&message->size_counters,                        free_size_counter, message);    _dbus_list_clear (&message->size_counters); -   -  _dbus_string_free (&message->header); + +  _dbus_header_free (&message->header);    _dbus_string_free (&message->body); -   +    dbus_free (message);  }  /* Message Cache - *  + *   * We cache some DBusMessage to reduce the overhead of allocating   * them.  In my profiling this consistently made about an 8%   * difference.  It avoids the malloc for the message, the malloc for @@ -1425,7 +504,7 @@ dbus_message_finalize (DBusMessage *message)   *      string_init_preallocated 3.43   *        dbus_malloc            2.43   *      dbus_malloc0             2.59 - *  + *   *    unref                      4.02   *      string_free              1.82   *        dbus_free              1.63 @@ -1458,13 +537,13 @@ dbus_message_cache_shutdown (void *data)      {        if (message_cache[i])          dbus_message_finalize (message_cache[i]); -       +        ++i;      }    message_cache_count = 0;    message_cache_shutdown_registered = FALSE; -   +    _DBUS_UNLOCK (message_cache);  } @@ -1482,11 +561,11 @@ dbus_message_get_cached (void)    int i;    message = NULL; -   +    _DBUS_LOCK (message_cache);    _dbus_assert (message_cache_count >= 0); -   +    if (message_cache_count == 0)      {        _DBUS_UNLOCK (message_cache); @@ -1498,7 +577,7 @@ dbus_message_get_cached (void)     * registered     */    _dbus_assert (message_cache_shutdown_registered); -   +    i = 0;    while (i < MAX_MESSAGE_CACHE_SIZE)      { @@ -1519,7 +598,7 @@ dbus_message_get_cached (void)    _dbus_assert (message->refcount.value == 0);    _dbus_assert (message->size_counters == NULL); -   +    return message;  } @@ -1535,16 +614,16 @@ dbus_message_cache_or_finalize (DBusMessage *message)    int i;    _dbus_assert (message->refcount.value == 0); -   +    /* This calls application code and has to be done first thing     * without holding the lock     */    _dbus_data_slot_list_clear (&message->slot_list); -   +    _dbus_list_foreach (&message->size_counters,                        free_size_counter, message);    _dbus_list_clear (&message->size_counters); -   +    was_cached = FALSE;    _DBUS_LOCK (message_cache); @@ -1552,7 +631,7 @@ dbus_message_cache_or_finalize (DBusMessage *message)    if (!message_cache_shutdown_registered)      {        _dbus_assert (message_cache_count == 0); -       +        if (!_dbus_register_shutdown_func (dbus_message_cache_shutdown, NULL))          goto out; @@ -1562,17 +641,17 @@ dbus_message_cache_or_finalize (DBusMessage *message)            message_cache[i] = NULL;            ++i;          } -       +        message_cache_shutdown_registered = TRUE;      }    _dbus_assert (message_cache_count >= 0); -   -  if ((_dbus_string_get_length (&message->header) + + +  if ((_dbus_string_get_length (&message->header.data) +         _dbus_string_get_length (&message->body)) >        MAX_MESSAGE_SIZE_TO_CACHE)      goto out; -   +    if (message_cache_count >= MAX_MESSAGE_CACHE_SIZE)      goto out; @@ -1587,7 +666,7 @@ dbus_message_cache_or_finalize (DBusMessage *message)    message_cache[i] = message;    message_cache_count += 1;    was_cached = TRUE; -   +   out:    _DBUS_UNLOCK (message_cache); @@ -1599,7 +678,6 @@ static DBusMessage*  dbus_message_new_empty_header (void)  {    DBusMessage *message; -  int i;    dbus_bool_t from_cache;    message = dbus_message_get_cached (); @@ -1621,47 +699,35 @@ dbus_message_new_empty_header (void)    message->refcount.value = 1;    message->byte_order = DBUS_COMPILER_BYTE_ORDER; -  message->client_serial = 0; -  message->reply_serial = 0;    message->locked = FALSE; -  message->header_padding = 0;    message->size_counters = NULL;    message->size_counter_delta = 0;    message->changed_stamp = 0;    if (!from_cache)      _dbus_data_slot_list_init (&message->slot_list); -   -  i = 0; -  while (i <= DBUS_HEADER_FIELD_LAST) -    { -      message->header_fields[i].name_offset  = -1; -      message->header_fields[i].value_offset = -1; -      ++i; -    }    if (from_cache)      { -      /* These can't fail since they shorten the string */ -      _dbus_string_set_length (&message->header, 0); +      _dbus_header_reinit (&message->header, message->byte_order);        _dbus_string_set_length (&message->body, 0);      }    else      { -      if (!_dbus_string_init_preallocated (&message->header, 32)) +      if (!_dbus_header_init (&message->header, message->byte_order))          {            dbus_free (message);            return NULL;          } -       +        if (!_dbus_string_init_preallocated (&message->body, 32))          { -          _dbus_string_free (&message->header); +          _dbus_header_free (&message->header);            dbus_free (message);            return NULL;          }      } -   +    return message;  } @@ -1679,41 +745,41 @@ dbus_message_new (int message_type)    DBusMessage *message;    _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL); -   +    message = dbus_message_new_empty_header ();    if (message == NULL)      return NULL; -   -  if (!dbus_message_create_header (message, -                                   message_type, -                                   NULL, NULL, NULL, NULL, NULL)) + +  if (!_dbus_header_create (&message->header, +                            message_type, +                            NULL, NULL, NULL, NULL, NULL))      {        dbus_message_unref (message);        return NULL;      } -   +    return message;  }  /**   * Constructs a new message to invoke a method on a remote   * object. Returns #NULL if memory can't be allocated for the - * message. The service may be #NULL in which case no service is set; - * this is appropriate when using D-BUS in a peer-to-peer context (no - * message bus). The interface may be #NULL, which means that - * if multiple methods with the given name exist it is undefined + * message. The destination may be #NULL in which case no destination + * is set; this is appropriate when using D-BUS in a peer-to-peer + * context (no message bus). The interface may be #NULL, which means + * that if multiple methods with the given name exist it is undefined   * which one will be invoked.    * - * @param service service that the message should be sent to or #NULL + * @param destination service that the message should be sent to or #NULL   * @param path object path the message should be sent to   * @param interface interface to invoke method on   * @param method method to invoke - *  + *   * @returns a new DBusMessage, free with dbus_message_unref()   * @see dbus_message_unref()   */  DBusMessage* -dbus_message_new_method_call (const char *service, +dbus_message_new_method_call (const char *destination,                                const char *path,                                const char *interface,                                const char *method) @@ -1722,19 +788,25 @@ dbus_message_new_method_call (const char *service,    _dbus_return_val_if_fail (path != NULL, NULL);    _dbus_return_val_if_fail (method != NULL, NULL); -   +  _dbus_return_val_if_fail (destination == NULL || +                            _dbus_check_is_valid_service (destination), NULL); +  _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); +  _dbus_return_val_if_fail (interface == NULL || +                            _dbus_check_is_valid_interface (interface), NULL); +  _dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL); +    message = dbus_message_new_empty_header ();    if (message == NULL)      return NULL; -   -  if (!dbus_message_create_header (message, -                                   DBUS_MESSAGE_TYPE_METHOD_CALL, -                                   service, path, interface, method, NULL)) + +  if (!_dbus_header_create (&message->header, +                            DBUS_MESSAGE_TYPE_METHOD_CALL, +                            destination, path, interface, method, NULL))      {        dbus_message_unref (message);        return NULL;      } -   +    return message;  } @@ -1746,7 +818,7 @@ dbus_message_new_method_call (const char *service,   * message is a reply to.   * @returns a new DBusMessage, free with dbus_message_unref()   * @see dbus_message_new_method_call(), dbus_message_unref() - */  + */  DBusMessage*  dbus_message_new_method_return (DBusMessage *method_call)  { @@ -1754,20 +826,18 @@ dbus_message_new_method_return (DBusMessage *method_call)    const char *sender;    _dbus_return_val_if_fail (method_call != NULL, NULL); -   -  sender = get_string_field (method_call, -                             DBUS_HEADER_FIELD_SENDER, -			     NULL); -   + +  sender = dbus_message_get_sender (method_call); +    /* sender is allowed to be null here in peer-to-peer case */    message = dbus_message_new_empty_header ();    if (message == NULL)      return NULL; -   -  if (!dbus_message_create_header (message, -                                   DBUS_MESSAGE_TYPE_METHOD_RETURN, -                                   sender, NULL, NULL, NULL, NULL)) + +  if (!_dbus_header_create (&message->header, +                            DBUS_MESSAGE_TYPE_METHOD_RETURN, +                            sender, NULL, NULL, NULL, NULL))      {        dbus_message_unref (message);        return NULL; @@ -1787,9 +857,9 @@ dbus_message_new_method_return (DBusMessage *method_call)  /**   * Constructs a new message representing a signal emission. Returns - * #NULL if memory can't be allocated for the message. - * A signal is identified by its originating interface, and - * the name of the signal. + * #NULL if memory can't be allocated for the message.  A signal is + * identified by its originating interface, and the name of the + * signal.   *   * @param path the path to the object emitting the signal   * @param interface the interface the signal is emitted from @@ -1807,21 +877,24 @@ dbus_message_new_signal (const char *path,    _dbus_return_val_if_fail (path != NULL, NULL);    _dbus_return_val_if_fail (interface != NULL, NULL);    _dbus_return_val_if_fail (name != NULL, NULL); -   +  _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); +  _dbus_return_val_if_fail (_dbus_check_is_valid_interface (interface), NULL); +  _dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL); +    message = dbus_message_new_empty_header ();    if (message == NULL)      return NULL; -   -  if (!dbus_message_create_header (message, -                                   DBUS_MESSAGE_TYPE_SIGNAL, -                                   NULL, path, interface, name, NULL)) + +  if (!_dbus_header_create (&message->header, +                            DBUS_MESSAGE_TYPE_SIGNAL, +                            NULL, path, interface, name, NULL))      {        dbus_message_unref (message);        return NULL;      }    dbus_message_set_no_reply (message, TRUE); -   +    return message;  } @@ -1845,11 +918,9 @@ dbus_message_new_error (DBusMessage *reply_to,    _dbus_return_val_if_fail (reply_to != NULL, NULL);    _dbus_return_val_if_fail (error_name != NULL, NULL); -  _dbus_return_val_if_fail (is_valid_error_name (error_name), NULL); -   -  sender = get_string_field (reply_to, -                             DBUS_HEADER_FIELD_SENDER, -			     NULL); +  _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); + +  sender = dbus_message_get_sender (reply_to);    /* sender may be NULL for non-message-bus case or     * when the message bus is dealing with an unregistered @@ -1858,17 +929,17 @@ dbus_message_new_error (DBusMessage *reply_to,    message = dbus_message_new_empty_header ();    if (message == NULL)      return NULL; -   -  if (!dbus_message_create_header (message, -                                   DBUS_MESSAGE_TYPE_ERROR, -                                   sender, NULL, NULL, NULL, error_name)) + +  if (!_dbus_header_create (&message->header, +                            DBUS_MESSAGE_TYPE_ERROR, +                            sender, NULL, NULL, NULL, error_name))      {        dbus_message_unref (message);        return NULL;      }    dbus_message_set_no_reply (message, TRUE); -   +    if (!dbus_message_set_reply_serial (message,                                        dbus_message_get_serial (reply_to)))      { @@ -1879,13 +950,15 @@ dbus_message_new_error (DBusMessage *reply_to,    if (error_message != NULL)      {        dbus_message_append_iter_init (message, &iter); -      if (!dbus_message_iter_append_string (&iter, error_message)) +      if (!dbus_message_iter_append_basic (&iter, +                                           DBUS_TYPE_STRING, +                                           &error_message))          {            dbus_message_unref (message);            return NULL;          }      } -   +    return message;  } @@ -1895,8 +968,8 @@ dbus_message_new_error (DBusMessage *reply_to,   *   * @param reply_to the original message   * @param error_name the error name - * @param error_format the error message string to be printed - * @param ... value of first argument, list of additional values to print + * @param error_format the error message format as with printf + * @param ... format string arguments   * @returns a new error message   */  DBusMessage* @@ -1911,8 +984,8 @@ dbus_message_new_error_printf (DBusMessage *reply_to,    _dbus_return_val_if_fail (reply_to != NULL, NULL);    _dbus_return_val_if_fail (error_name != NULL, NULL); -  _dbus_return_val_if_fail (is_valid_error_name (error_name), NULL); -   +  _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); +    if (!_dbus_string_init (&str))      return NULL; @@ -1923,7 +996,7 @@ dbus_message_new_error_printf (DBusMessage *reply_to,  				      _dbus_string_get_const_data (&str));    else      message = NULL; -   +    _dbus_string_free (&str);    va_end (args); @@ -1934,7 +1007,10 @@ dbus_message_new_error_printf (DBusMessage *reply_to,  /**   * Creates a new message that is an exact replica of the message - * specified, except that its refcount is set to 1. + * specified, except that its refcount is set to 1, its message serial + * is reset to 0, and if the original message was "locked" (in the + * outgoing message queue and thus not modifiable) the new message + * will not be locked.   *   * @param message the message.   * @returns the new message. @@ -1943,60 +1019,46 @@ DBusMessage *  dbus_message_copy (const DBusMessage *message)  {    DBusMessage *retval; -  int i;    _dbus_return_val_if_fail (message != NULL, NULL); -   +    retval = dbus_new0 (DBusMessage, 1);    if (retval == NULL)      return NULL; -   +    retval->refcount.value = 1;    retval->byte_order = message->byte_order; -  retval->client_serial = message->client_serial; -  retval->reply_serial = message->reply_serial; -  retval->header_padding = message->header_padding;    retval->locked = FALSE;  #ifndef DBUS_DISABLE_CHECKS    retval->generation = message->generation;  #endif -   -  if (!_dbus_string_init_preallocated (&retval->header, -                                       _dbus_string_get_length (&message->header))) + +  if (!_dbus_header_copy (&message->header, &retval->header))      {        dbus_free (retval);        return NULL;      } -   +    if (!_dbus_string_init_preallocated (&retval->body,                                         _dbus_string_get_length (&message->body)))      { -      _dbus_string_free (&retval->header); +      _dbus_header_free (&retval->header);        dbus_free (retval);        return NULL;      } -   -  if (!_dbus_string_copy (&message->header, 0, -			  &retval->header, 0)) -    goto failed_copy;    if (!_dbus_string_copy (&message->body, 0,  			  &retval->body, 0))      goto failed_copy; -   -  for (i = 0; i <= DBUS_HEADER_FIELD_LAST; i++) -    { -      retval->header_fields[i] = message->header_fields[i]; -    } -   +    return retval;   failed_copy: -  _dbus_string_free (&retval->header); +  _dbus_header_free (&retval->header);    _dbus_string_free (&retval->body);    dbus_free (retval); -   -  return NULL;   + +  return NULL;  } @@ -2014,7 +1076,7 @@ dbus_message_ref (DBusMessage *message)    _dbus_return_val_if_fail (message != NULL, NULL);    _dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL); -   +    old_refcount = _dbus_atomic_inc (&message->refcount);    _dbus_assert (old_refcount >= 1); @@ -2034,9 +1096,9 @@ dbus_message_unref (DBusMessage *message)    _dbus_return_if_fail (message != NULL);    _dbus_return_if_fail (message->generation == _dbus_current_generation); -   +    old_refcount = _dbus_atomic_dec (&message->refcount); -   +    _dbus_assert (old_refcount >= 0);    if (old_refcount == 1) @@ -2048,10 +1110,11 @@ dbus_message_unref (DBusMessage *message)  /**   * Gets the type of a message. Types include - * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN, - * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types - * are allowed and all code must silently ignore messages of unknown - * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however. + * #DBUS_MESSAGE_TYPE_METHOD_CALL, #DBUS_MESSAGE_TYPE_METHOD_RETURN, + * #DBUS_MESSAGE_TYPE_ERROR, #DBUS_MESSAGE_TYPE_SIGNAL, but other + * types are allowed and all code must silently ignore messages of + * unknown type. DBUS_MESSAGE_TYPE_INVALID will never be returned, + * however.   *   *   * @param message the message @@ -2060,246 +1123,64 @@ dbus_message_unref (DBusMessage *message)  int  dbus_message_get_type (DBusMessage *message)  { -  int type; - -  type = _dbus_string_get_byte (&message->header, 1); -  _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); - -  return type; -} - -/** - * Sets the object path this message is being sent to (for - * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being - * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL). - * - * @param message the message - * @param object_path the path or #NULL to unset - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_path (DBusMessage   *message, -                       const char    *object_path) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (message != NULL, DBUS_MESSAGE_TYPE_INVALID); -  return set_string_field (message, -                           DBUS_HEADER_FIELD_PATH, -                           DBUS_TYPE_OBJECT_PATH, -                           object_path); -} - -/** - * Gets the object path this message is being sent to - * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted - * from (for DBUS_MESSAGE_TYPE_SIGNAL). - * - * @param message the message - * @returns the path (should not be freed) - */ -const char* -dbus_message_get_path (DBusMessage   *message) -{ -  _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message, DBUS_HEADER_FIELD_PATH, NULL); +  return _dbus_header_get_message_type (&message->header);  }  /** - * Gets the object path this message is being sent to - * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted - * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed - * format (one array element per path component). - * Free the returned array with dbus_free_string_array(). - * - * An empty but non-NULL path array means the path "/". - * So the path "/foo/bar" becomes { "foo", "bar", NULL } - * and the path "/" becomes { NULL }. + * Appends fields to a message given a variable argument list. The + * variable argument list should contain the type of each argument + * followed by the value to append. Appendable types are basic types, + * and arrays of fixed-length basic types. To append variable-length + * basic types, or any more complex value, you have to use an iterator + * rather than this function.   * - * @param message the message - * @param path place to store allocated array of path components; #NULL set here if no path field exists - * @returns #FALSE if no memory to allocate the array - */ -dbus_bool_t -dbus_message_get_path_decomposed (DBusMessage   *message, -                                  char        ***path) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (path != NULL, FALSE); - -  return get_path_field_decomposed (message, -				    DBUS_HEADER_FIELD_PATH, -                                    path); -} - -/** - * Sets the interface this message is being sent to - * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or - * the interface a signal is being emitted from - * (for DBUS_MESSAGE_TYPE_SIGNAL). + * To append a basic type, specify its type code followed by the + * value. For example:   * - * @param message the message - * @param interface the interface or #NULL to unset - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_interface (DBusMessage  *message, -                            const char   *interface) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); - -  return set_string_field (message, -                           DBUS_HEADER_FIELD_INTERFACE, -                           DBUS_TYPE_STRING, -                           interface); -} - -/** - * Gets the interface this message is being sent to - * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted - * from (for DBUS_MESSAGE_TYPE_SIGNAL). - * The interface name is fully-qualified (namespaced). + * @code + * DBUS_TYPE_INT32, 42, + * DBUS_TYPE_STRING, "Hello World" + * @endcode + * or + * @code + * dbus_int32_t val = 42; + * DBUS_TYPE_INT32, val + * @endcode   * - * @param message the message - * @returns the message interface (should not be freed) - */ -const char* -dbus_message_get_interface (DBusMessage *message) -{ -  _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message, DBUS_HEADER_FIELD_INTERFACE, NULL); -} - -/** - * Sets the interface member being invoked - * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted - * (DBUS_MESSAGE_TYPE_SIGNAL). - * The interface name is fully-qualified (namespaced). + * Be sure that your provided value is the right size. For example, this + * won't work: + * @code + * DBUS_TYPE_INT64, 42 + * @endcode + * Because the "42" will be a 32-bit integer. You need to cast to + * 64-bit.   * - * @param message the message - * @param member the member or #NULL to unset - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_member (DBusMessage  *message, -                       const char   *member) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); - -  return set_string_field (message, -                           DBUS_HEADER_FIELD_MEMBER, -                           DBUS_TYPE_STRING, -                           member); -} - -/** - * Gets the interface member being invoked - * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted - * (DBUS_MESSAGE_TYPE_SIGNAL). - *  - * @param message the message - * @returns the member name (should not be freed) - */ -const char* -dbus_message_get_member (DBusMessage *message) -{ -  _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message, -			   DBUS_HEADER_FIELD_MEMBER, -			   NULL); -} - -/** - * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR). - * The name is fully-qualified (namespaced). + * To append an array of fixed-length basic types, pass in the + * DBUS_TYPE_ARRAY typecode, the element typecode, the address of + * the array pointer, and a 32-bit integer giving the number of + * elements in the array. So for example: + * @code + * const dbus_int32_t array[] = { 1, 2, 3 }; + * const dbus_int32_t *v_ARRAY = array; + * DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3 + * @endcode   * - * @param message the message - * @param error_name the name or #NULL to unset - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_error_name (DBusMessage  *message, -                             const char   *error_name) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); -  _dbus_return_val_if_fail (error_name == NULL || is_valid_error_name (error_name), FALSE); -   -  return set_string_field (message, -                           DBUS_HEADER_FIELD_ERROR_NAME, -                           DBUS_TYPE_STRING, -                           error_name); -} - -/** - * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only). - *  - * @param message the message - * @returns the error name (should not be freed) - */ -const char* -dbus_message_get_error_name (DBusMessage *message) -{ -  _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message, -			   DBUS_HEADER_FIELD_ERROR_NAME, -			   NULL); -} - -/** - * Sets the message's destination service. + * @warning in C, given "int array[]", "&array == array" (the + * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). + * So if you're using an array instead of a pointer you have to create + * a pointer variable, assign the array to it, then take the address + * of the pointer variable. For strings it works to write + * const char *array = "Hello" and then use &array though.   * - * @param message the message - * @param destination the destination service name or #NULL to unset - * @returns #FALSE if not enough memory - */ -dbus_bool_t -dbus_message_set_destination (DBusMessage  *message, -                              const char   *destination) -{ -  _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (!message->locked, FALSE); - -  return set_string_field (message, -                           DBUS_HEADER_FIELD_DESTINATION, -                           DBUS_TYPE_STRING, -                           destination); -} - -/** - * Gets the destination service of a message. - *  - * @param message the message - * @returns the message destination service (should not be freed) - */ -const char* -dbus_message_get_destination (DBusMessage *message) -{ -  _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message, -			   DBUS_HEADER_FIELD_DESTINATION, -			   NULL); -} - -/** - * Appends fields to a message given a variable argument list. The - * variable argument list should contain the type of the argument - * followed by the value to add.  Array values are specified by an int - * typecode followed by a pointer to the array followed by an int - * giving the length of the array.  The argument list must be - * terminated with #DBUS_TYPE_INVALID. + * The last argument to this function must be #DBUS_TYPE_INVALID, + * marking the end of the argument list.   * - * This function doesn't support dicts or non-fundamental arrays. + * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays   * - * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64 - * only if #DBUS_HAVE_INT64 is defined. + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message.   *   * @param message the message   * @param first_arg_type type of the first argument @@ -2308,14 +1189,14 @@ dbus_message_get_destination (DBusMessage *message)   */  dbus_bool_t  dbus_message_append_args (DBusMessage *message, -			  int first_arg_type, +			  int          first_arg_type,  			  ...)  {    dbus_bool_t retval;    va_list var_args;    _dbus_return_val_if_fail (message != NULL, FALSE); -   +    va_start (var_args, first_arg_type);    retval = dbus_message_append_args_valist (message,  					    first_arg_type, @@ -2325,26 +1206,128 @@ dbus_message_append_args (DBusMessage *message,    return retval;  } -/* Swap into our byte order if message isn't already. - * Done only when required, which allows the bus to avoid - * ever doing this as it routes messages. +/** + * This function takes a va_list for use by language bindings. + * It's otherwise the same as dbus_message_append_args(). + * + * @todo for now, if this function fails due to OOM it will leave + * the message half-written and you have to discard the message + * and start over. + * + * @see dbus_message_append_args. + * @param message the message + * @param first_arg_type type of first argument + * @param var_args value of first argument, then list of type/value pairs + * @returns #TRUE on success   */ -static void -_dbus_message_ensure_our_byte_order (DBusMessage *message) +dbus_bool_t +dbus_message_append_args_valist (DBusMessage *message, +				 int          first_arg_type, +				 va_list      var_args)  { -  if (message->byte_order == DBUS_COMPILER_BYTE_ORDER) -    return; +  int type; +  DBusMessageIter iter; + +  _dbus_return_val_if_fail (message != NULL, FALSE); + +  type = first_arg_type; + +  dbus_message_append_iter_init (message, &iter); + +  while (type != DBUS_TYPE_INVALID) +    { +      if (_dbus_type_is_basic (type)) +        { +          const DBusBasicValue *value; +          value = va_arg (var_args, const DBusBasicValue*); + +          if (!dbus_message_iter_append_basic (&iter, +                                               type, +                                               value)) +            goto failed; +        } +      else if (type == DBUS_TYPE_ARRAY) +        { +          int element_type; +          const DBusBasicValue **value; +          int n_elements; +          DBusMessageIter array; +          char buf[2]; + +          element_type = va_arg (var_args, int); + +#ifndef DBUS_DISABLE_CHECKS +          if (!_dbus_type_is_fixed (element_type)) +            { +              _dbus_warn ("arrays of %s can't be appended with %s for now\n", +                          _dbus_type_to_string (element_type), +                          _DBUS_FUNCTION_NAME); +              goto failed; +            } +#endif + +          value = va_arg (var_args, const DBusBasicValue**); +          n_elements = va_arg (var_args, int); + +          buf[0] = element_type; +          buf[1] = '\0'; +          if (!dbus_message_iter_open_container (&iter, +                                                 DBUS_TYPE_ARRAY, +                                                 buf, +                                                 &array)) +            goto failed; + +          if (!dbus_message_iter_append_fixed_array (&array, +                                                     element_type, +                                                     value, +                                                     n_elements)) +            goto failed; + +          if (!dbus_message_iter_close_container (&iter, &array)) +            goto failed; +        } +#ifndef DBUS_DISABLE_CHECKS +      else +        { +          _dbus_warn ("type %s isn't supported yet in %s\n", +                      _dbus_type_to_string (type), _DBUS_FUNCTION_NAME); +          goto failed; +        } +#endif -   +      type = va_arg (var_args, int); +    } +  return TRUE; + failed: +  return FALSE;  }  /** - * Gets arguments from a message given a variable argument list. - * The variable argument list should contain the type of the - * argumen followed by a pointer to where the value should be - * stored. The list is terminated with #DBUS_TYPE_INVALID. + * Gets arguments from a message given a variable argument list.  The + * supported types include those supported by + * dbus_message_append_args(); that is, basic types and arrays of + * fixed-length basic types.  The arguments are the same as they would + * be for dbus_message_iter_get_basic() or + * dbus_message_iter_get_fixed_array(). + * + * In addition to those types, arrays of string, object path, and + * signature are supported; but these are returned as allocated memory + * and must be freed with dbus_free_string_array(), while the other + * types are returned as const references. + * + * The variable argument list should contain the type of the argument + * followed by a pointer to where the value should be stored. The list + * is terminated with #DBUS_TYPE_INVALID. + * + * The returned values are constant; do not free them. They point + * into the #DBusMessage. + * + * If the requested arguments are not present, or do not have the + * requested types, then an error will be set. + * + * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays   *   * @param message the message   * @param error error to be filled in on failure @@ -2363,7 +1346,7 @@ dbus_message_get_args (DBusMessage     *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_error_is_set (error, FALSE); -   +    va_start (var_args, first_arg_type);    retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args);    va_end (var_args); @@ -2372,9 +1355,8 @@ dbus_message_get_args (DBusMessage     *message,  }  /** - * This function takes a va_list for use by language bindings - * - * @todo We need to free the argument data when an error occurs. + * This function takes a va_list for use by language bindings. It is + * otherwise the same as dbus_message_get_args().   *   * @see dbus_message_get_args   * @param message the message @@ -2393,24 +1375,28 @@ dbus_message_get_args_valist (DBusMessage     *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _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);  }  /** - * Gets arguments from a message iterator given a variable argument list. - * The variable argument list should contain the type of the - * argumen followed by a pointer to where the value should be - * stored. The list is terminated with 0. + * 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.   * - * @param iter the message iterator  + * @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   */ -dbus_bool_t +static dbus_bool_t  dbus_message_iter_get_args (DBusMessageIter *iter,  			    DBusError       *error,  			    int              first_arg_type, @@ -2421,7 +1407,7 @@ dbus_message_iter_get_args (DBusMessageIter *iter,    _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); @@ -2429,8 +1415,21 @@ dbus_message_iter_get_args (DBusMessageIter *iter,    return retval;  } +static void +_dbus_message_iter_init_common (DBusMessage         *message, +                                DBusMessageRealIter *real, +                                int                  iter_type) +{ +  _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); + +  real->message = message; +  real->changed_stamp = message->changed_stamp; +  real->iter_type = iter_type; +  real->sig_refcount = 0; +} +  /** - * Initializes a DBusMessageIter representing the arguments of the + * Initializes a #DBusMessageIter for reading the arguments of the   * message passed in.   *   * @param message the message @@ -2442,124 +1441,67 @@ dbus_message_iter_init (DBusMessage     *message,  			DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  const DBusString *type_str; +  int type_pos;    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (iter != NULL, FALSE); -   -  _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); -   -  real->message = message; -  real->parent_iter = NULL; -  real->changed_stamp = message->changed_stamp; -   -  real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE; -  real->pos = 0; -  real->end = _dbus_string_get_length (&message->body); -   -  real->container_start = 0; -  real->container_length_pos = 0; -  real->wrote_dict_key = 0; -  real->array_type_pos = 0; - -  return real->end > real->pos; + +  get_const_signature (&message->header, &type_str, &type_pos); + +  _dbus_message_iter_init_common (message, real, +                                  DBUS_MESSAGE_ITER_TYPE_READER); + +  _dbus_type_reader_init (&real->u.reader, +                          message->byte_order, +                          type_str, type_pos, +                          &message->body, +                          0); + +  return _dbus_type_reader_has_next (&real->u.reader);  }  #ifndef DBUS_DISABLE_CHECKS  static dbus_bool_t -dbus_message_iter_check (DBusMessageRealIter *iter) +_dbus_message_iter_check (DBusMessageRealIter *iter)  {    if (iter == NULL)      { -      _dbus_warn ("dbus iterator check failed: iterator is NULL\n"); +      _dbus_warn ("dbus message iterator is NULL\n");        return FALSE;      } -   -  if (iter->changed_stamp != iter->message->changed_stamp) + +  if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER)      { -      _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message\n"); -      return FALSE; +      if (iter->u.reader.byte_order != iter->message->byte_order) +        { +          _dbus_warn ("dbus message changed byte order since iterator was created\n"); +          return FALSE; +        }      } -   -  if (iter->pos < 0 || iter->pos > iter->end) +  else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)      { -      _dbus_warn ("dbus iterator check failed: invalid position\n"); -      return FALSE; +      if (iter->u.writer.byte_order != iter->message->byte_order) +        { +          _dbus_warn ("dbus message changed byte order since append iterator was created\n"); +          return FALSE; +        }      } - -  return TRUE; -} -#endif /* DBUS_DISABLE_CHECKS */ - -static int -skip_array_type (DBusMessageRealIter *iter, int pos) -{ -  const char *data; - -  do +  else      { -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      pos++, 1); +      _dbus_warn ("dbus message iterator looks uninitialized or corrupted\n"); +      return FALSE;      } -  while (*data == DBUS_TYPE_ARRAY); -   -  return pos; -} -/* FIXME what are these _dbus_type_is_valid() checks for? - * haven't we validated the message? - */ -static int -dbus_message_iter_get_data_start (DBusMessageRealIter *iter, int *type) -{ -  const char *data; -  int pos, len; -   -  switch (iter->type) +  if (iter->changed_stamp != iter->message->changed_stamp)      { -    case DBUS_MESSAGE_ITER_TYPE_MESSAGE: -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      iter->pos, 1); -      if (_dbus_type_is_valid (*data)) -	*type = *data; -      else -	*type = DBUS_TYPE_INVALID; -       -      return skip_array_type (iter, iter->pos); -       -    case DBUS_MESSAGE_ITER_TYPE_ARRAY: -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      iter->array_type_pos, 1); -      if (_dbus_type_is_valid (*data)) -	*type = *data; -      else -	*type = DBUS_TYPE_INVALID; -       -      return iter->pos; -       -    case DBUS_MESSAGE_ITER_TYPE_DICT: -      /* Get the length of the string */ -      len = _dbus_demarshal_uint32 (&iter->message->body, -				    iter->message->byte_order, -				    iter->pos, &pos); -      pos = pos + len + 1; - -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      pos, 1); -      if (_dbus_type_is_valid (*data)) -	*type = *data; -      else -	*type = DBUS_TYPE_INVALID; - -      return skip_array_type (iter, pos); -       -    default: -      _dbus_assert_not_reached ("Invalid iter type"); -      break; +      _dbus_warn ("dbus message iterator invalid because the message has been modified (or perhaps the iterator is just uninitialized)\n"); +      return FALSE;      } -  *type = DBUS_TYPE_INVALID; -  return iter->pos; -} +  return TRUE; +} +#endif /* DBUS_DISABLE_CHECKS */  /**   * Checks if an iterator has any more fields. @@ -2572,287 +1514,191 @@ dbus_bool_t  dbus_message_iter_has_next (DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int end_pos; -  int type, pos; -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); +  _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); -  if (real->pos >= real->end) -    return FALSE; -   -  pos = dbus_message_iter_get_data_start (real, &type); -   -  if (!_dbus_marshal_get_arg_end_pos (&real->message->body, -                                      real->message->byte_order, -				      type, pos, &end_pos)) -    return FALSE; -   -  if (end_pos >= real->end) -    return FALSE; - -  return TRUE;   +  return _dbus_type_reader_has_next (&real->u.reader);  }  /** - * Moves the iterator to the next field. + * Moves the iterator to the next field, if any. If there's no next + * field, returns #FALSE. If the iterator moves forward, returns + * #TRUE.   * - * @param iter The message iter + * @param iter the message iter   * @returns #TRUE if the iterator was moved to the next field   */  dbus_bool_t  dbus_message_iter_next (DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int end_pos; -  int type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); - -  pos = dbus_message_iter_get_data_start (real, &type); -   -  if (!_dbus_marshal_get_arg_end_pos (&real->message->body, -                                      real->message->byte_order, -				      type, pos, &end_pos)) -    return FALSE; - -  if (end_pos >= real->end) -    return FALSE; -  real->pos = end_pos; +  _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); -  return TRUE; +  return _dbus_type_reader_next (&real->u.reader);  }  /** - * Returns the argument type of the argument that the - * message iterator points at. + * Returns the argument type of the argument that the message iterator + * points to. If the iterator is at the end of the message, returns + * #DBUS_TYPE_INVALID. You can thus write a loop as follows: + * + * @code + * dbus_message_iter_init (&iter); + * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) + *   dbus_message_iter_next (&iter); + * @endcode   *   * @param iter the message iter - * @returns the field type + * @returns the argument type   */  int  dbus_message_iter_get_arg_type (DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID); - -  if (real->pos >= real->end) -    { -      _dbus_verbose ("  iterator at or beyond end of message\n"); -      return DBUS_TYPE_INVALID; -    } -  pos = dbus_message_iter_get_data_start (real, &type); -   -  return type; -} - -/* FIXME why do we validate the typecode in here, hasn't the message - * already been verified? - */ -static int -iter_get_array_type (DBusMessageRealIter *iter, int *array_type_pos) -{ -  const char *data; -  int _array_type_pos; -  int len, pos; -   -  switch (iter->type) -    { -    case DBUS_MESSAGE_ITER_TYPE_MESSAGE: -      _array_type_pos = iter->pos + 1; -      break; -    case DBUS_MESSAGE_ITER_TYPE_ARRAY: -      _array_type_pos = iter->array_type_pos + 1; -      break; -    case DBUS_MESSAGE_ITER_TYPE_DICT: -      /* Get the length of the string */ -      len = _dbus_demarshal_uint32 (&iter->message->body, -				    iter->message->byte_order, -				    iter->pos, &pos); -      pos = pos + len + 1; -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      pos + 1, 1); -      _array_type_pos = pos + 1; -      break; -    default: -      _dbus_assert_not_reached ("wrong iter type"); -      return DBUS_TYPE_INVALID; -    } +  _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); -  if (array_type_pos != NULL) -    *array_type_pos = _array_type_pos; -   -  data = _dbus_string_get_const_data_len (&iter->message->body, -					  _array_type_pos, 1); -  if (_dbus_type_is_valid (*data)) -    return  *data; -   -  return DBUS_TYPE_INVALID; +  return _dbus_type_reader_get_current_type (&real->u.reader);  } -  /** - * Returns the element type of the array that the - * message iterator points at. Note that you need - * to check that the iterator points to an array - * prior to using this function. + * Returns the element type of the array that the message iterator + * points to. Note that you need to check that the iterator points to + * an array prior to using this function.   *   * @param iter the message iter - * @returns the field type + * @returns the array element type   */  int  dbus_message_iter_get_array_type (DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID); - -  if (real->pos >= real->end) -    return DBUS_TYPE_INVALID; -  pos = dbus_message_iter_get_data_start (real, &type); +  _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, DBUS_TYPE_INVALID); +  _dbus_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID); -  _dbus_assert (type == DBUS_TYPE_ARRAY); - -  return iter_get_array_type (real, NULL); +  return _dbus_type_reader_get_array_type (&real->u.reader);  } -  /** - * Returns the string value that an iterator may point to. - * Note that you need to check that the iterator points to - * a string value before using this function. + * Recurses into a container value when reading values from a message, + * initializing a sub-iterator to use for traversing the child values + * of the container.   * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the string + * Note that this recurses into a value, not a type, so you can only + * recurse if the value exists. The main implication of this is that + * if you have for example an empty array of array of int32, you can + * recurse into the outermost array, but it will have no values, so + * you won't be able to recurse further. There's no array of int32 to + * recurse into. + * + * @param iter the message iterator + * @param sub the sub-iterator to initialize   */ -char * -dbus_message_iter_get_string (DBusMessageIter *iter) +void +dbus_message_iter_recurse (DBusMessageIter  *iter, +                           DBusMessageIter  *sub)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; +  DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; -  _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL); -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_STRING); +  _dbus_return_if_fail (_dbus_message_iter_check (real)); +  _dbus_return_if_fail (sub != NULL); -  return _dbus_demarshal_string (&real->message->body, real->message->byte_order, -                                 pos, NULL); +  *real_sub = *real; +  _dbus_type_reader_recurse (&real->u.reader, &real_sub->u.reader);  }  /** - * Returns the object path value that an iterator may point to. - * Note that you need to check that the iterator points to - * an object path value before using this function. + * Reads a basic-typed value from the message iterator. + * Basic types are the non-containers such as integer and string.   * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the path + * The value argument should be the address of a location to store + * the returned value. So for int32 it should be a "dbus_int32_t*" + * and for string a "const char**". The returned value is + * by reference and should not be freed. + * + * All returned values are guaranteed to fit in 8 bytes. So you can + * write code like this: + * + * @code + * #ifdef DBUS_HAVE_INT64 + * dbus_uint64_t value; + * int type; + * dbus_message_iter_get_basic (&read_iter, &value); + * type = dbus_message_iter_get_arg_type (&read_iter); + * dbus_message_iter_append_basic (&write_iter, type, &value); + * #endif + * @endcode + * + * To avoid the #DBUS_HAVE_INT64 conditional, create a struct or + * something that occupies at least 8 bytes, e.g. you could use a + * struct with two int32 values in it. dbus_uint64_t is just one + * example of a type that's large enough to hold any possible value. + * + * Be sure you have somehow checked that + * dbus_message_iter_get_arg_type() matches the type you are + * expecting, or you'll crash when you try to use an integer as a + * string or something. + * + * @param iter the iterator + * @param value location to store the value   */ -char * -dbus_message_iter_get_object_path (DBusMessageIter  *iter) +void +dbus_message_iter_get_basic (DBusMessageIter  *iter, +                             void             *value)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL); -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_OBJECT_PATH); +  _dbus_return_if_fail (_dbus_message_iter_check (real)); +  _dbus_return_if_fail (value != NULL); -  return _dbus_demarshal_string (&real->message->body, real->message->byte_order, -                                 pos, NULL); +  _dbus_type_reader_read_basic (&real->u.reader, +                                value);  }  /** - * Returns the name and data from a custom type that an iterator may - * point to. Note that you need to check that the iterator points to a - * custom type before using this function. + * Reads a block of fixed-length values from the message iterator. + * Fixed-length values are those basic types that are not string-like, + * such as integers, bool, double. The block read will be from the + * current position in the array until the end of the array.   * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @param name return location for the name of the custom type - * @param value return location for data - * @param len return location for length of data - * @returns TRUE if get succeed - *  + * The value argument should be the address of a location to store the + * returned array. So for int32 it should be a "const dbus_int32_t**" + * The returned value is by reference and should not be freed. + * + * @param iter the iterator + * @param value location to store the block + * @param n_elements number of elements in the block   */ -dbus_bool_t -dbus_message_iter_get_custom (DBusMessageIter   *iter, -                              char             **name, -                              unsigned char    **value, -                              int               *len) +void +dbus_message_iter_get_fixed_array (DBusMessageIter  *iter, +                                   void             *value, +                                   int              *n_elements)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; -  char *_name; -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); +  _dbus_return_if_fail (_dbus_message_iter_check (real)); +  _dbus_return_if_fail (value != NULL); +  _dbus_return_if_fail (_dbus_type_is_fixed (_dbus_type_reader_get_array_type (&real->u.reader))); -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_CUSTOM); -   -  _name = _dbus_demarshal_string (&real->message->body, real->message->byte_order, -				  pos, &pos); - -  if (_name == NULL) -    return FALSE; -   -  if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order, -				   pos, NULL, value, len)) -    { -      dbus_free (_name); -      return FALSE; -    } - -  *name = _name; -   -  return TRUE; -} - -static void -_dbus_message_iter_get_basic_type (DBusMessageIter *iter, -				   char             type, -				   void            *value) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int item_type, pos; - -  _dbus_return_if_fail (dbus_message_iter_check (real)); - -  pos = dbus_message_iter_get_data_start (real, &item_type); -   -  _dbus_assert (type == item_type); -   -  _dbus_demarshal_basic_type (&real->message->body, -			      type, value, -			      real->message->byte_order, -			      &pos); +  _dbus_type_reader_read_fixed_multi (&real->u.reader, +                                      value, n_elements);  } -  /** - * This function takes a va_list for use by language bindings - * - * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64 - * only if #DBUS_HAVE_INT64 is defined. - * - * @todo this function (or some lower-level non-convenience function) - * needs better error handling; should allow the application to - * distinguish between out of memory, and bad data from the remote - * app. It also needs to not leak a bunch of args when it gets - * to the arg that's bad, as that would be a security hole - * (allow one app to force another to leak memory) + * This function takes a va_list for use by language bindings and is + * otherwise the same as dbus_message_iter_get_args(). + * dbus_message_get_args() is the place to go for complete + * documentation.   * - * @todo We need to free the argument data when an error occurs. + * @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 @@ -2861,27 +1707,28 @@ _dbus_message_iter_get_basic_type (DBusMessageIter *iter,   * @param var_args return location for first argument, followed by list of type/location pairs   * @returns #FALSE if error was set   */ -dbus_bool_t +static 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 (iter != NULL, FALSE); +  _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE);    _dbus_return_val_if_error_is_set (error, FALSE);    retval = FALSE; -   +    spec_type = first_arg_type;    i = 0; -   +    while (spec_type != DBUS_TYPE_INVALID)      { -      msg_type = dbus_message_iter_get_arg_type (iter);       -       +      msg_type = dbus_message_iter_get_arg_type (iter); +        if (msg_type != spec_type)  	{            dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, @@ -2893,750 +1740,305 @@ dbus_message_iter_get_args_valist (DBusMessageIter *iter,            goto out;  	} -      switch (spec_type) -	{ -	case DBUS_TYPE_NIL: -	  break; -	case DBUS_TYPE_BOOLEAN: -	  { -	    dbus_bool_t *ptr; - -	    ptr = va_arg (var_args, dbus_bool_t *); - -	    *ptr = dbus_message_iter_get_boolean (iter); -	    break; -	  } -	case DBUS_TYPE_BYTE: -	case DBUS_TYPE_INT32: -	case DBUS_TYPE_UINT32: -#ifdef DBUS_HAVE_INT64 -	case DBUS_TYPE_INT64: -	case DBUS_TYPE_UINT64: -#endif /* DBUS_HAVE_INT64 */ -	case DBUS_TYPE_DOUBLE: -	  { -	    void *ptr = va_arg (var_args, double *); -	    _dbus_message_iter_get_basic_type (iter, spec_type, ptr); -	    break; -	  } - -	case DBUS_TYPE_STRING: -	  { -	    char **ptr; - -	    ptr = va_arg (var_args, char **); - -	    *ptr = dbus_message_iter_get_string (iter); - -	    if (!*ptr) -              { -                dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -                goto out; -              } -	     -	    break; -	  } - -	  case DBUS_TYPE_OBJECT_PATH: -	  { -	    char **ptr; - -	    ptr = va_arg (var_args, char **); - -	    *ptr = dbus_message_iter_get_object_path (iter); - -	    if (!*ptr) -	      { -	        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -	        goto out; -	      } - -	    break; -	  } - -	case DBUS_TYPE_CUSTOM: -	  { -	    char **name; -	    unsigned char **data; -	    int *len; -  -	    name = va_arg (var_args, char **); -	    data = va_arg (var_args, unsigned char **); -	    len = va_arg (var_args, int *); - -	    if (!dbus_message_iter_get_custom (iter, name, data, len)) -	      { -                dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -		goto out; -	      } -	  } -	  break; -	case DBUS_TYPE_ARRAY: -	  { -	    void **data; -	    int *len, type; -	    dbus_bool_t err = FALSE; -  -	    type = va_arg (var_args, int); -	    data = va_arg (var_args, void *); -	    len = va_arg (var_args, int *); - -            _dbus_return_val_if_fail (data != NULL, FALSE); -            _dbus_return_val_if_fail (len != NULL, FALSE); -             -	    if (dbus_message_iter_get_array_type (iter) != type) -	      { -		dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, -				"Argument %d is specified to be of type \"array of %s\", but " -				"is actually of type \"array of %s\"\n", i, -				_dbus_type_to_string (type), -				_dbus_type_to_string (dbus_message_iter_get_array_type (iter))); -		goto out; -	      } -	     -	    switch (type) -	      { -	      case DBUS_TYPE_BYTE: -		err = !dbus_message_iter_get_byte_array (iter, (unsigned char **)data, len); -		break; -	      case DBUS_TYPE_BOOLEAN: -		err = !dbus_message_iter_get_boolean_array (iter, (unsigned char **)data, len); -		break; -	      case DBUS_TYPE_INT32: -		err = !dbus_message_iter_get_int32_array (iter, (dbus_int32_t **)data, len); -		break; -	      case DBUS_TYPE_UINT32: -		err = !dbus_message_iter_get_uint32_array (iter, (dbus_uint32_t **)data, len); -		break; -#ifdef DBUS_HAVE_INT64 -              case DBUS_TYPE_INT64: -		err = !dbus_message_iter_get_int64_array (iter, (dbus_int64_t **)data, len); -		break; -	      case DBUS_TYPE_UINT64: -		err = !dbus_message_iter_get_uint64_array (iter, (dbus_uint64_t **)data, len); -		break; -#endif /* DBUS_HAVE_INT64 */ -	      case DBUS_TYPE_DOUBLE: -		err = !dbus_message_iter_get_double_array (iter, (double **)data, len); -		break; -	      case DBUS_TYPE_STRING: -		err = !dbus_message_iter_get_string_array (iter, (char ***)data, len); -		break; -	      case DBUS_TYPE_OBJECT_PATH: -	        err = !dbus_message_iter_get_object_path_array (iter, (char ***)data, len); -	        break; - -	      case DBUS_TYPE_NIL: -	      case DBUS_TYPE_ARRAY: -	      case DBUS_TYPE_CUSTOM: -	      case DBUS_TYPE_DICT: -		_dbus_warn ("dbus_message_get_args_valist doesn't support recursive arrays\n"); -		dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL); -		goto out; -	      default: -		_dbus_warn ("Unknown field type %d\n", type); -		dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL); -		goto out; -	      } -	    if (err) -	      { -	        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -		goto out; -	      } -	  } -	  break; -	case DBUS_TYPE_DICT: -	  _dbus_warn ("dbus_message_get_args_valist doesn't support dicts\n"); -	  dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL); -	  goto out; -	default:	   -	  dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL); -	  _dbus_warn ("Unknown field type %d\n", spec_type); -	  goto out; -	} - -      spec_type = va_arg (var_args, int); -      if (!dbus_message_iter_next (iter) && spec_type != DBUS_TYPE_INVALID) +      if (_dbus_type_is_basic (spec_type))          { -          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, -                          "Message has only %d arguments, but more were expected", i); -          goto out; -        } - -      i++; -    } -   -  retval = TRUE; -   - out: -   -  return retval; -} - -/** - * Returns the byte value that an iterator may point to. - * Note that you need to check that the iterator points to - * a byte value before using this function. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the byte value - */ -unsigned char -dbus_message_iter_get_byte (DBusMessageIter *iter) -{ -  unsigned char value = 0; - -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_BYTE, &value); - -  return value; -} - -/** - * Returns the boolean value that an iterator may point to. - * Note that you need to check that the iterator points to - * a boolean value before using this function. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the boolean value - */ -dbus_bool_t -dbus_message_iter_get_boolean (DBusMessageIter *iter) -{ -  unsigned char value = 0; - -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_BOOLEAN, &value); - -  return (value != FALSE); -} - -/** - * Returns the 32 bit signed integer value that an iterator may point to. - * Note that you need to check that the iterator points to - * a 32-bit integer value before using this function. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the integer - */ -dbus_int32_t -dbus_message_iter_get_int32 (DBusMessageIter *iter) -{ -  dbus_int32_t value = 0; +          DBusBasicValue *ptr; -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_INT32, &value); +          ptr = va_arg (var_args, DBusBasicValue*); -  return value; -} +          _dbus_return_val_if_fail (ptr != NULL, FALSE); -/** - * Returns the 32 bit unsigned integer value that an iterator may point to. - * Note that you need to check that the iterator points to - * a 32-bit unsigned integer value before using this function. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the integer - */ -dbus_uint32_t -dbus_message_iter_get_uint32 (DBusMessageIter *iter) -{ -  dbus_int32_t value = 0; - -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_UINT32, &value); - -  return value; -} +          _dbus_type_reader_read_basic (&real->u.reader, +                                        ptr); +        } +      else if (spec_type == DBUS_TYPE_ARRAY) +        { +          int element_type; +          int spec_element_type; +          const DBusBasicValue **ptr; +          int *n_elements_p; +          DBusTypeReader array; -#ifdef DBUS_HAVE_INT64 +          spec_element_type = va_arg (var_args, int); +          element_type = _dbus_type_reader_get_array_type (&real->u.reader); -/** - * Returns the 64 bit signed integer value that an iterator may point - * to.  Note that you need to check that the iterator points to a - * 64-bit integer value before using this function. - * - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the integer - */ -dbus_int64_t -dbus_message_iter_get_int64 (DBusMessageIter *iter) -{ -  dbus_int64_t value = 0; +          if (spec_element_type != element_type) +            { +              dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, +                              "Argument %d is specified to be an array of \"%s\", but " +                              "is actually an array of \"%s\"\n", +                              i, +                              _dbus_type_to_string (spec_element_type), +                              _dbus_type_to_string (element_type)); + +              goto out; +            } -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_INT64, &value); +          if (_dbus_type_is_fixed (spec_element_type)) +            { +              ptr = va_arg (var_args, const DBusBasicValue**); +              n_elements_p = va_arg (var_args, int*); -  return value; -} +              _dbus_return_val_if_fail (ptr != NULL, FALSE); +              _dbus_return_val_if_fail (n_elements_p != NULL, FALSE); -/** - * Returns the 64 bit unsigned integer value that an iterator may point to. - * Note that you need to check that the iterator points to - * a 64-bit unsigned integer value before using this function. - *  - * This function only exists if #DBUS_HAVE_INT64 is defined. - *  - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the integer - */ -dbus_uint64_t -dbus_message_iter_get_uint64 (DBusMessageIter *iter) -{ -  dbus_uint64_t value = 0; +              _dbus_type_reader_recurse (&real->u.reader, &array); -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_UINT64, &value); +              _dbus_type_reader_read_fixed_multi (&array, +                                                  ptr, n_elements_p); +            } +          else if (spec_element_type == DBUS_TYPE_STRING || +                   spec_element_type == DBUS_TYPE_SIGNATURE || +                   spec_element_type == DBUS_TYPE_OBJECT_PATH) +            { +              char ***str_array_p; +              int i; +              char **str_array; + +              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); + +              /* Count elements in the array */ +              _dbus_type_reader_recurse (&real->u.reader, &array); + +              i = 0; +              if (_dbus_type_reader_has_next (&array)) +                { +                  while (_dbus_type_reader_next (&array)) +                    ++i; +                } + +              str_array = dbus_new0 (char*, i + 1); +              if (str_array == NULL) +                { +                  _DBUS_SET_OOM (error); +                  goto out; +                } + +              /* Now go through and dup each string */ +              _dbus_type_reader_recurse (&real->u.reader, &array); + +              i = 0; +              if (_dbus_type_reader_has_next (&array)) +                { +                  do +                    { +                      const char *s; +                      _dbus_type_reader_read_basic (&array, +                                                    &s); + +                      str_array[i] = _dbus_strdup (s); +                      if (str_array[i] == NULL) +                        { +                          dbus_free_string_array (str_array); +                          _DBUS_SET_OOM (error); +                          goto out; +                        } + +                      ++i; +                    } +                  while (_dbus_type_reader_next (&array)); +                } + +              *str_array_p = str_array; +              *n_elements_p = i; +            } +#ifndef DBUS_DISABLE_CHECKS +          else +            { +              _dbus_warn ("you can't read arrays of container types (struct, variant, array) with %s for now\n", +                          _DBUS_FUNCTION_NAME); +              goto out; +            } +#endif +        } +#ifndef DBUS_DISABLE_CHECKS +      else +        { +          _dbus_warn ("you can only read arrays and basic types with %s for now\n", +                      _DBUS_FUNCTION_NAME); +          goto out; +        } +#endif -  return value; -} +      spec_type = va_arg (var_args, int); +      if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID) +        { +          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, +                          "Message has only %d arguments, but more were expected", i); +          goto out; +        } -#endif /* DBUS_HAVE_INT64 */ +      i++; +    } -/** - * Returns the double value that an iterator may point to. - * Note that you need to check that the iterator points to - * a string value before using this function. - * - * @see dbus_message_iter_get_arg_type - * @param iter the message iter - * @returns the double - */ -double -dbus_message_iter_get_double (DBusMessageIter *iter) -{ -  double value = 0.0; +  retval = TRUE; -  _dbus_message_iter_get_basic_type (iter, DBUS_TYPE_DOUBLE, &value); + out: -  return value; +  return retval;  }  /** - * Initializes an iterator for the array that the iterator - * may point to. Note that you need to check that the iterator - * points to an array prior to using this function. + * Initializes a #DBusMessageIter for appending arguments to the end + * of a message.   * - * The array element type is returned in array_type, and the array - * iterator can only be used to get that type of data. - * - * @param iter the iterator - * @param array_iter pointer to an iterator to initialize - * @param array_type gets set to the type of the array elements - * @returns #FALSE if the array is empty - */ -dbus_bool_t -dbus_message_iter_init_array_iterator (DBusMessageIter *iter, -				       DBusMessageIter *array_iter, -				       int             *array_type) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter; -  int type, pos, len_pos, len, array_type_pos; -  int _array_type; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); - -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_ARRAY); - -  _array_type = iter_get_array_type (real, &array_type_pos); -   -  len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t)); -  len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order, -				pos, &pos); -   -  array_real->parent_iter = real; -  array_real->message = real->message; -  array_real->changed_stamp = real->message->changed_stamp; -   -  array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY; -  array_real->pos = pos; -  array_real->end = pos + len; -   -  array_real->container_start = pos; -  array_real->container_length_pos = len_pos; -  array_real->wrote_dict_key = 0; -  array_real->array_type_pos = array_type_pos; -  array_real->array_type_done = TRUE; -   -  if (array_type != NULL) -    *array_type = _array_type; - -  return len > 0; -} - - -/** - * Initializes an iterator for the dict that the iterator - * may point to. Note that you need to check that the iterator - * points to a dict prior to using this function. + * @todo If appending any of the arguments fails due to lack of + * memory, generally the message is hosed and you have to start over + * building the whole message.   * - * @param iter the iterator - * @param dict_iter pointer to an iterator to initialize - * @returns #FALSE if the dict is empty + * @param message the message + * @param iter pointer to an iterator to initialize   */ -dbus_bool_t -dbus_message_iter_init_dict_iterator (DBusMessageIter *iter, -				      DBusMessageIter *dict_iter) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter; -  int type, pos, len_pos, len; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); - -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_DICT); - -  len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t)); -  len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order, -				pos, &pos); -   -  dict_real->parent_iter = real; -  dict_real->message = real->message; -  dict_real->changed_stamp = real->message->changed_stamp; -   -  dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT; -  dict_real->pos = pos; -  dict_real->end = pos + len; -   -  dict_real->container_start = pos; -  dict_real->container_length_pos = len_pos; -  dict_real->wrote_dict_key = 0; - -  return len > 0; -} - -static dbus_bool_t -_dbus_message_iter_get_basic_type_array  (DBusMessageIter *iter, -					  char             type, -					  void           **array, -					  int             *array_len) +void +dbus_message_append_iter_init (DBusMessage     *message, +			       DBusMessageIter *iter)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int item_type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); - -  pos = dbus_message_iter_get_data_start (real, &item_type); -   -  _dbus_assert (item_type == DBUS_TYPE_ARRAY); -  item_type = iter_get_array_type (real, NULL); -   -  _dbus_assert (type == item_type); - -  return _dbus_demarshal_basic_type_array (&real->message->body, -					   item_type, array, array_len, -					   real->message->byte_order, &pos); -} - -/** - * Returns the byte array that the iterator may point to. - * Note that you need to check that the iterator points - * to a byte array prior to using this function. - * - * @param iter the iterator - * @param value return location for array values - * @param len return location for length of byte array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_byte_array (DBusMessageIter  *iter, -				  unsigned char   **value, -                                  int              *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_BYTE, -						  (void **) value, len); -} +  _dbus_return_if_fail (message != NULL); +  _dbus_return_if_fail (iter != NULL); -/** - * Returns the boolean array that the iterator may point to. Note that - * you need to check that the iterator points to an array of the - * correct type prior to using this function. - * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_boolean_array (DBusMessageIter   *iter, -				     unsigned char    **value, -				     int               *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_BOOLEAN, -						  (void **) value, len); -} +  _dbus_message_iter_init_common (message, real, +                                  DBUS_MESSAGE_ITER_TYPE_WRITER); -/** - * Returns the 32 bit signed integer array that the iterator may point - * to. Note that you need to check that the iterator points to an - * array of the correct type prior to using this function. - * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_int32_array  (DBusMessageIter *iter, -				    dbus_int32_t   **value, -				    int             *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_INT32, -						  (void **) value, len); +  /* We create the signature string and point iterators at it "on demand" +   * when a value is actually appended. That means that init() never fails +   * due to OOM. +   */ +  _dbus_type_writer_init_types_delayed (&real->u.writer, +                                        message->byte_order, +                                        &message->body, +                                        _dbus_string_get_length (&message->body));  }  /** - * Returns the 32 bit unsigned integer array that the iterator may point - * to. Note that you need to check that the iterator points to an - * array of the correct type prior to using this function. + * Creates a temporary signature string containing the current + * signature, stores it in the iterator, and points the iterator to + * the end of it. Used any time we write to the message.   * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success + * @param real an iterator without a type_str + * @returns #FALSE if no memory   */ -dbus_bool_t -dbus_message_iter_get_uint32_array  (DBusMessageIter *iter, -				     dbus_uint32_t  **value, -				     int             *len) +static dbus_bool_t +_dbus_message_iter_open_signature (DBusMessageRealIter *real)  { -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_UINT32, -						  (void **) value, len); -} +  DBusString *str; +  const DBusString *current_sig; +  int current_sig_pos; -#ifdef DBUS_HAVE_INT64 +  _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); -/** - * Returns the 64 bit signed integer array that the iterator may point - * to. Note that you need to check that the iterator points to an - * array of the correct type prior to using this function. - *  - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_int64_array  (DBusMessageIter *iter, -				    dbus_int64_t   **value, -				    int             *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_INT64, -						  (void **) value, len); -} +  if (real->u.writer.type_str != NULL) +    { +      _dbus_assert (real->sig_refcount > 0); +      real->sig_refcount += 1; +      return TRUE; +    } -/** - * Returns the 64 bit unsigned integer array that the iterator may point - * to. Note that you need to check that the iterator points to an - * array of the correct type prior to using this function. - * - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_uint64_array  (DBusMessageIter *iter, -				     dbus_uint64_t  **value, -				     int             *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_UINT64, -						  (void **) value, len); -} +  str = dbus_new (DBusString, 1); +  if (str == NULL) +    return FALSE; -#endif /* DBUS_HAVE_INT64 */ +  if (!_dbus_header_get_field_raw (&real->message->header, +                                   DBUS_HEADER_FIELD_SIGNATURE, +                                   ¤t_sig, ¤t_sig_pos)) +    current_sig = NULL; -/** - * Returns the double array that the iterator may point to. Note that - * you need to check that the iterator points to an array of the - * correct type prior to using this function. - * - * @param iter the iterator - * @param value return location for the array - * @param len return location for the array length - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_double_array  (DBusMessageIter *iter, -				     double         **value, -				     int             *len) -{ -  return _dbus_message_iter_get_basic_type_array (iter, DBUS_TYPE_DOUBLE, -						  (void **) value, len); -} +  if (current_sig) +    { +      int current_len; -/** - * Returns the string array that the iterator may point to. - * Note that you need to check that the iterator points - * to a string array prior to using this function. - * - * The returned value is a #NULL-terminated array of strings. - * Each string is a separate malloc block, and the array - * itself is a malloc block. You can free this type of - * string array with dbus_free_string_array(). - * - * @param iter the iterator - * @param value return location for string values - * @param len return location for length of byte array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_get_string_array (DBusMessageIter *iter, -				    char          ***value, -				    int             *len) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; +      current_len = _dbus_string_get_byte (current_sig, current_sig_pos); +      current_sig_pos += 1; /* move on to sig data */ -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); +      if (!_dbus_string_init_preallocated (str, current_len + 4)) +        { +          dbus_free (str); +          return FALSE; +        } -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_ARRAY); +      if (!_dbus_string_copy_len (current_sig, current_sig_pos, current_len, +                                  str, 0)) +        { +          _dbus_string_free (str); +          dbus_free (str); +          return FALSE; +        } +    } +  else +    { +      if (!_dbus_string_init_preallocated (str, 4)) +        { +          dbus_free (str); +          return FALSE; +        } +    } -  type = iter_get_array_type (real, NULL); -  _dbus_assert (type == DBUS_TYPE_STRING); +  real->sig_refcount = 1; -  if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order, -				     pos, NULL, value, len)) -    return FALSE; -  else -    return TRUE; +  _dbus_type_writer_add_types (&real->u.writer, +                               str, _dbus_string_get_length (str)); +  return TRUE;  }  /** - * Returns the object path array that the iterator may point to. - * Note that you need to check that the iterator points - * to an object path array prior to using this function. + * Sets the new signature as the message signature, frees the + * signature string, and marks the iterator as not having a type_str + * anymore. Frees the signature even if it fails, so you can't + * really recover from failure. Kinda busted.   * - * The returned value is a #NULL-terminated array of strings. - * Each string is a separate malloc block, and the array - * itself is a malloc block. You can free this type of - * array with dbus_free_string_array(). - * - * @param iter the iterator - * @param value return location for string values - * @param len return location for length of byte array - * @returns #TRUE on success + * @param real an iterator without a type_str + * @returns #FALSE if no memory   */ -dbus_bool_t -dbus_message_iter_get_object_path_array (DBusMessageIter *iter, -                                         char          ***value, -                                         int             *len) +static dbus_bool_t +_dbus_message_iter_close_signature (DBusMessageRealIter *real)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  int type, pos; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE); +  DBusString *str; +  const char *v_STRING; +  dbus_bool_t retval; -  pos = dbus_message_iter_get_data_start (real, &type); -   -  _dbus_assert (type == DBUS_TYPE_ARRAY); +  _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); +  _dbus_assert (real->u.writer.type_str != NULL); +  _dbus_assert (real->sig_refcount > 0); -  type = iter_get_array_type (real, NULL); -  _dbus_assert (type == DBUS_TYPE_OBJECT_PATH); +  real->sig_refcount -= 1; -  if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order, -				     pos, NULL, value, len)) -    return FALSE; -  else +  if (real->sig_refcount > 0)      return TRUE; -} +  _dbus_assert (real->sig_refcount == 0); -/** - * Returns the key name fot the dict entry that an iterator - * may point to. Note that you need to check that the iterator - * points to a dict entry before using this function. - * - * @see dbus_message_iter_init_dict_iterator - * @param iter the message iter - * @returns the key name - */ -char * -dbus_message_iter_get_dict_key (DBusMessageIter   *iter) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL); +  retval = TRUE; -  _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT); +  str = real->u.writer.type_str; -  return _dbus_demarshal_string (&real->message->body, real->message->byte_order, -                                 real->pos, NULL); -} +  v_STRING = _dbus_string_get_const_data (str); +  if (!_dbus_header_set_field_basic (&real->message->header, +                                     DBUS_HEADER_FIELD_SIGNATURE, +                                     DBUS_TYPE_SIGNATURE, +                                     &v_STRING)) +    retval = FALSE; -/** - * Initializes a DBusMessageIter pointing to the end of the - * message. This iterator can be used to append data to the - * message. - * - * @param message the message - * @param iter pointer to an iterator to initialize - */ -void -dbus_message_append_iter_init (DBusMessage     *message, -			       DBusMessageIter *iter) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  _dbus_type_writer_remove_types (&real->u.writer); +  _dbus_string_free (str); +  dbus_free (str); -  _dbus_return_if_fail (message != NULL); -  _dbus_return_if_fail (iter != NULL); -   -  real->message = message; -  real->parent_iter = NULL; -  real->changed_stamp = message->changed_stamp; -   -  real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE; -  real->end = _dbus_string_get_length (&real->message->body); -  real->pos = real->end; -   -  real->container_length_pos = 0; -  real->wrote_dict_key = 0; +  return retval;  }  #ifndef DBUS_DISABLE_CHECKS  static dbus_bool_t -dbus_message_iter_append_check (DBusMessageRealIter *iter) +_dbus_message_iter_append_check (DBusMessageRealIter *iter)  { -  if (iter == NULL) -    { -      _dbus_warn ("dbus iterator check failed: NULL iterator\n"); -      return FALSE; -    } -   +  if (!_dbus_message_iter_check (iter)) +    return FALSE; +    if (iter->message->locked)      { -      _dbus_warn ("dbus iterator check failed: message is locked (has already been sent)\n"); -      return FALSE; -    } -       -  if (iter->changed_stamp != iter->message->changed_stamp) -    { -      _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message"); -      return FALSE; -    } -   -  if (iter->pos != iter->end) -    { -      _dbus_warn ("dbus iterator check failed: can only append at end of message"); -      return FALSE; -    } -   -  if (iter->pos != _dbus_string_get_length (&iter->message->body)) -    { -      _dbus_warn ("dbus iterator check failed: append pos not at end of message string"); +      _dbus_warn ("dbus append iterator can't be used: message is locked (has already been sent)\n");        return FALSE;      } @@ -3644,1057 +2046,568 @@ dbus_message_iter_append_check (DBusMessageRealIter *iter)  }  #endif /* DBUS_DISABLE_CHECKS */ -static dbus_bool_t -dbus_message_iter_append_type (DBusMessageRealIter *iter, -			       int                  type) -{ -  const char *data; - -  switch (iter->type) -    { -    case DBUS_MESSAGE_ITER_TYPE_MESSAGE: -      if (!_dbus_string_append_byte (&iter->message->body, type)) -        return FALSE; - -      if (!_dbus_message_append_byte_to_signature (iter->message, type)) -        { -          _dbus_string_shorten (&iter->message->body, 1); -          return FALSE; -        } -      break; -       -    case DBUS_MESSAGE_ITER_TYPE_ARRAY: -      data = _dbus_string_get_const_data_len (&iter->message->body, -					      iter->array_type_pos, 1); -      if (type != *data) -	{ -	  _dbus_warn ("Appended element of wrong type for array\n"); -	  return FALSE; -	} -      break; -       -    case DBUS_MESSAGE_ITER_TYPE_DICT: -      if (!iter->wrote_dict_key) -	{ -	  _dbus_warn ("Appending dict data before key name\n"); -	  return FALSE; -	} -       -      if (!_dbus_string_append_byte (&iter->message->body, type)) -        return FALSE; -       -      break; -       -    default: -      _dbus_assert_not_reached ("Invalid iter type"); -      break; -    } -   -  return TRUE; -} - -static void -dbus_message_iter_update_after_change (DBusMessageRealIter *iter) -{ -  iter->changed_stamp = iter->message->changed_stamp; -   -  /* Set new end of iter */ -  iter->end = _dbus_string_get_length (&iter->message->body); -  iter->pos = iter->end; - -  /* Set container length */ -  if (iter->type == DBUS_MESSAGE_ITER_TYPE_DICT || -      (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY && iter->array_type_done)) -    _dbus_marshal_set_uint32 (&iter->message->body, -			      iter->message->byte_order, -			      iter->container_length_pos, -			      iter->end - iter->container_start); -   -  if (iter->parent_iter) -    dbus_message_iter_update_after_change (iter->parent_iter); -} - -static void -dbus_message_iter_append_done (DBusMessageRealIter *iter) -{ -  iter->message->changed_stamp++; -  dbus_message_iter_update_after_change (iter); -  iter->wrote_dict_key = FALSE; -} -  /** - * Appends a nil value to the message + * Appends a basic-typed value to the message. The basic types are the + * non-container types such as integer and string.   * - * @param iter an iterator pointing to the end of the message - * @returns #TRUE on success + * The "value" argument should be the address of a basic-typed value. + * So for string, const char**. For integer, dbus_int32_t*. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param type the type of the value + * @param value the address of the value + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_nil (DBusMessageIter *iter) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_NIL)) -    return FALSE; -   -  dbus_message_iter_append_done (real); -   -  return TRUE; -} - -static dbus_bool_t  dbus_message_iter_append_basic (DBusMessageIter *iter, -				char             type, -				void            *value) +                                int              type, +                                const void      *value)  {    DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  dbus_bool_t ret; -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); +  _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); +  _dbus_return_val_if_fail (_dbus_type_is_basic (type), FALSE); +  _dbus_return_val_if_fail (value != NULL, FALSE); -  if (!dbus_message_iter_append_type (real, type)) +  if (!_dbus_message_iter_open_signature (real))      return FALSE; -  if (!_dbus_marshal_basic_type (&real->message->body, -				 type, value, -				 real->message->byte_order)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  ret = _dbus_type_writer_write_basic (&real->u.writer, type, value); -  dbus_message_iter_append_done (real); -   -  return TRUE;   -} +  if (!_dbus_message_iter_close_signature (real)) +    ret = FALSE; -/** - * Appends a boolean value to the message - * - * @param iter an iterator pointing to the end of the message - * @param value the boolean value - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_boolean (DBusMessageIter *iter, -				  dbus_bool_t     value) -{ -  unsigned char val = (value != FALSE); -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &val); +  return ret;  }  /** - * Appends a byte to the message + * Appends a block of fixed-length values to an array. The + * fixed-length types are all basic types that are not string-like. So + * int32, double, bool, etc. You must call + * dbus_message_iter_open_container() to open an array of values + * before calling this function. You may call this function multiple + * times (and intermixed with calls to + * dbus_message_iter_append_basic()) for the same array.   * - * @param iter an iterator pointing to the end of the message - * @param value the byte value - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_byte (DBusMessageIter *iter, -			       unsigned char    value) -{ -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &value); -} - -/** - * Appends a 32 bit signed integer to the message. + * The "value" argument should be the address of the array.  So for + * integer, "dbus_int32_t**" is expected for example.   * - * @param iter an iterator pointing to the end of the message - * @param value the integer value - * @returns #TRUE on success + * @warning in C, given "int array[]", "&array == array" (the + * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). + * So if you're using an array instead of a pointer you have to create + * a pointer variable, assign the array to it, then take the address + * of the pointer variable. + * @code + * const dbus_int32_t array[] = { 1, 2, 3 }; + * const dbus_int32_t *v_ARRAY = array; + * if (!dbus_message_iter_append_fixed_array (&iter, DBUS_TYPE_INT32, &v_ARRAY, 3)) + *   fprintf (stderr, "No memory!\n"); + * @endcode + * For strings it works to write const char *array = "Hello" and then + * use &array though. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param type the type of the array elements + * @param value the address of the array + * @param n_elements the number of elements to append + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_int32   (DBusMessageIter *iter, -				  dbus_int32_t  value) +dbus_message_iter_append_fixed_array (DBusMessageIter *iter, +                                      int              element_type, +                                      const void      *value, +                                      int              n_elements)  { -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &value); -} - -/** - * Appends a 32 bit unsigned integer to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the integer value - * @returns #TRUE on success +  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  dbus_bool_t ret; + +  _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); +  _dbus_return_val_if_fail (_dbus_type_is_fixed (element_type), FALSE); +  _dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE); +  _dbus_return_val_if_fail (value != NULL, FALSE); +  _dbus_return_val_if_fail (n_elements >= 0, FALSE); +  _dbus_return_val_if_fail (n_elements <= +                            DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type), +                            FALSE); + +  ret = _dbus_type_writer_write_fixed_multi (&real->u.writer, element_type, value, n_elements); + +  return ret; +} + +/** + * Appends a container-typed value to the message; you are required to + * append the contents of the container using the returned + * sub-iterator, and then call + * dbus_message_iter_close_container(). Container types are for + * example struct, variant, and array. For variants, the + * contained_signature should be the type of the single value inside + * the variant. For structs, contained_signature should be #NULL; it + * will be set to whatever types you write into the struct.  For + * arrays, contained_signature should be the type of the array + * elements. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param type the type of the value + * @param contained_signature the type of container contents + * @param sub sub-iterator to initialize + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_uint32 (DBusMessageIter *iter, -				 dbus_uint32_t    value) +dbus_message_iter_open_container (DBusMessageIter *iter, +                                  int              type, +                                  const char      *contained_signature, +                                  DBusMessageIter *sub)  { -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &value); -} +  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; +  DBusString contained_str; + +  _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); +  _dbus_return_val_if_fail (_dbus_type_is_container (type), FALSE); +  _dbus_return_val_if_fail (sub != NULL, FALSE); +  _dbus_return_val_if_fail ((type == DBUS_TYPE_STRUCT && +                             contained_signature == NULL) || +                            contained_signature != NULL, FALSE); + +  if (!_dbus_message_iter_open_signature (real)) +    return FALSE; -#ifdef DBUS_HAVE_INT64 +  _dbus_string_init_const (&contained_str, contained_signature); -/** - * Appends a 64 bit signed integer to the message. - * - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @param iter an iterator pointing to the end of the message - * @param value the integer value - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_int64   (DBusMessageIter *iter, -				  dbus_int64_t  value) -{ -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &value); +  *real_sub = *real; +  return _dbus_type_writer_recurse (&real->u.writer, +                                    type, +                                    &contained_str, 0, +                                    &real_sub->u.writer);  } +  /** - * Appends a 64 bit unsigned integer to the message. + * Closes a container-typed value appended to the message; may write + * out more information to the message known only after the entire + * container is written, and may free resources created by + * dbus_message_iter_open_container().   * - * This function only exists if #DBUS_HAVE_INT64 is defined. + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message.   * - * @param iter an iterator pointing to the end of the message - * @param value the integer value - * @returns #TRUE on success + * @param iter the append iterator + * @param sub sub-iterator to close + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_uint64 (DBusMessageIter *iter, -				 dbus_uint64_t    value) +dbus_message_iter_close_container (DBusMessageIter *iter, +                                   DBusMessageIter *sub)  { -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &value); -} +  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; +  dbus_bool_t ret; -#endif /* DBUS_HAVE_INT64 */ +  _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); +  _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); +  _dbus_return_val_if_fail (_dbus_message_iter_append_check (real_sub), FALSE); +  _dbus_return_val_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); -/** - * Appends a double value to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the double value - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_double (DBusMessageIter *iter, -				 double           value) -{ -  return dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &value); +  ret = _dbus_type_writer_unrecurse (&real->u.writer, +                                     &real_sub->u.writer); + +  if (!_dbus_message_iter_close_signature (real)) +    ret = FALSE; + +  return ret;  }  /** - * Appends a UTF-8 string to the message. - * - * @todo add return_val_if_fail(UTF-8 is valid) + * Sets a flag indicating that the message does not want a reply; if + * this flag is set, the other end of the connection may (but is not + * required to) optimize by not sending method return or error + * replies. If this flag is set, there is no way to know whether the + * message successfully arrived at the remote end. Normally you know a + * message was received when you receive the reply to it.   * - * @param iter an iterator pointing to the end of the message - * @param value the string - * @returns #TRUE on success + * @param message the message + * @param no_reply #TRUE if no reply is desired   */ -dbus_bool_t -dbus_message_iter_append_string (DBusMessageIter *iter, -				 const char      *value) +void +dbus_message_set_no_reply (DBusMessage *message, +                           dbus_bool_t  no_reply)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); -   -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_STRING)) -    return FALSE; -   -  if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_if_fail (message != NULL); +  _dbus_return_if_fail (!message->locked); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  _dbus_header_toggle_flag (&message->header, +                            DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, +                            no_reply);  }  /** - * Appends an object path to the message. - * - * @todo add return_val_if_fail(UTF-8 is valid) + * Returns #TRUE if the message does not expect + * a reply.   * - * @param iter an iterator pointing to the end of the message - * @param value the object path - * @returns #TRUE on success + * @param message the message + * @returns #TRUE if the message sender isn't waiting for a reply   */  dbus_bool_t -dbus_message_iter_append_object_path (DBusMessageIter *iter, -				      const char      *value) +dbus_message_get_no_reply (DBusMessage *message)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); -   -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_OBJECT_PATH)) -    return FALSE; -   -  if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_val_if_fail (message != NULL, FALSE); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  return _dbus_header_get_flag (&message->header, +                                DBUS_HEADER_FLAG_NO_REPLY_EXPECTED);  }  /** - * Appends a custom type data chunk to the message. A custom - * type is simply an arbitrary UTF-8 string used as a type - * tag, plus an array of arbitrary bytes to be interpreted - * according to the type tag. - * - * @param iter an iterator pointing to the end of the message - * @param name the name of the type - * @param data the binary data used to store the value - * @param len the length of the binary data in bytes - * @returns #TRUE on success + * Sets a flag indicating that the addressed service will be + * auto-activated before the message is delivered. When this flag is + * set, the message is held until the service is succesfully activated + * or fails to activate. In case of failure, the reply will be an + * activation error. If this flag is not set (the default + * + * @param message the message + * @param auto_activation #TRUE if auto-activation is desired   */ -dbus_bool_t -dbus_message_iter_append_custom (DBusMessageIter      *iter, -                                 const char           *name, -                                 const unsigned char  *data, -                                 int                   len) +void +dbus_message_set_auto_activation (DBusMessage *message, +				  dbus_bool_t  auto_activation)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_CUSTOM)) -    return FALSE; -   -   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, name)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } -    -  if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, data, len)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_if_fail (message != NULL); +  _dbus_return_if_fail (!message->locked); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  _dbus_header_toggle_flag (&message->header, +                            DBUS_HEADER_FLAG_AUTO_ACTIVATION, +                            auto_activation);  } -  /** - * Appends a dict key name to the message. The iterator used - * must point to a dict. + * Returns #TRUE if the message will cause the addressed service to be + * auto-activated.   * - * @param iter an iterator pointing to the end of the message - * @param value the string - * @returns #TRUE on success + * @param message the message + * @returns #TRUE if the message will use auto-activation   */  dbus_bool_t -dbus_message_iter_append_dict_key (DBusMessageIter *iter, -				   const char      *value) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); -  _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT); -   -  if (real->wrote_dict_key) -    { -      _dbus_warn ("Appending multiple dict key names\n"); -      return FALSE; -    } -   -  if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value)) -    { -      return FALSE; -    } - -  dbus_message_iter_append_done (real); -  real->wrote_dict_key = TRUE; -   -  return TRUE; -} - -static dbus_bool_t -array_iter_type_mark_done (DBusMessageRealIter *iter) +dbus_message_get_auto_activation (DBusMessage *message)  { -  int len_pos; -   -  if (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY) -    array_iter_type_mark_done (iter->parent_iter); -  else -    return TRUE; - -  len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&iter->message->body), -			       sizeof (dbus_uint32_t)); - -  /* Empty length for now, backfill later */ -  if (!_dbus_marshal_uint32 (&iter->message->body, iter->message->byte_order, 0)) -    { -      _dbus_string_set_length (&iter->message->body, iter->pos); -      return FALSE; -    } - -  iter->container_start = _dbus_string_get_length (&iter->message->body); -  iter->container_length_pos = len_pos; -  iter->array_type_done = TRUE; +  _dbus_return_val_if_fail (message != NULL, FALSE); -  return TRUE; +  return _dbus_header_get_flag (&message->header, +                                DBUS_HEADER_FLAG_AUTO_ACTIVATION);  } -static dbus_bool_t -append_array_type (DBusMessageRealIter *real, -		   int                  element_type, -		   dbus_bool_t         *array_type_done, -		   int                 *array_type_pos) -{ -  int existing_element_type; -   -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_ARRAY)) -    return FALSE; -   -  if (real->type == DBUS_MESSAGE_ITER_TYPE_ARRAY && -      real->array_type_done) -    { -      existing_element_type = iter_get_array_type (real, array_type_pos); -      if (existing_element_type != element_type) -	{ -	  _dbus_warn ("Appending array of %s, when expecting array of %s\n", -		      _dbus_type_to_string (element_type), -                      _dbus_type_to_string (existing_element_type)); -	  _dbus_string_set_length (&real->message->body, real->pos); -	  return FALSE; -	} -      if (array_type_done != NULL) -	  *array_type_done = TRUE; -    } -  else -    { -      if (array_type_pos != NULL) -	*array_type_pos = _dbus_string_get_length (&real->message->body); - - -      if (!_dbus_message_append_byte_to_signature (real->message, element_type)) -        { -          _dbus_string_set_length (&real->message->body, real->pos); -          return FALSE; -        } -       -      /* Append element type */ -      if (!_dbus_string_append_byte (&real->message->body, element_type)) -	{ -          _dbus_message_remove_byte_from_signature (real->message); -	  _dbus_string_set_length (&real->message->body, real->pos); -	  return FALSE; -	} - -      if (array_type_done != NULL) -	*array_type_done = element_type != DBUS_TYPE_ARRAY; -       -      if (element_type != DBUS_TYPE_ARRAY && -	  !array_iter_type_mark_done (real)) -        { -          _dbus_message_remove_byte_from_signature (real->message); -          return FALSE; -        } -    } - -  return TRUE; -}  /** - * Appends an array to the message and initializes an iterator that - * can be used to append to the array. + * Sets the object path this message is being sent to (for + * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being + * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL).   * - * @param iter an iterator pointing to the end of the message - * @param array_iter pointer to an iter that will be initialized - * @param element_type the type of the array elements - * @returns #TRUE on success + * @param message the message + * @param object_path the path or #NULL to unset + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_array (DBusMessageIter      *iter, -				DBusMessageIter      *array_iter, -				int                   element_type) +dbus_message_set_path (DBusMessage   *message, +                       const char    *object_path)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter; -  int len_pos; -  int array_type_pos; -  dbus_bool_t array_type_done; - -  if (element_type == DBUS_TYPE_NIL) -    { -      _dbus_warn ("Can't create NIL arrays\n"); -      return FALSE; -    } -   -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!append_array_type (real, element_type, &array_type_done, &array_type_pos)) -    return FALSE; - -  len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t)); +  _dbus_return_val_if_fail (message != NULL, FALSE); +  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (object_path == NULL || +                            _dbus_check_is_valid_path (object_path), +                            FALSE); -  if (array_type_done) -    { -      /* Empty length for now, backfill later */ -      if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0)) -	{ -	  _dbus_string_set_length (&real->message->body, real->pos); -	  return FALSE; -	} -    } -   -  array_real->parent_iter = real; -  array_real->message = real->message; -  array_real->changed_stamp = real->message->changed_stamp; -   -  array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY; -  array_real->pos = _dbus_string_get_length (&real->message->body); -  array_real->end = array_real->end; -   -  array_real->container_start = array_real->pos; -  array_real->container_length_pos = len_pos; -  array_real->wrote_dict_key = 0; -  array_real->array_type_done = array_type_done; -  array_real->array_type_pos = array_type_pos; - -  dbus_message_iter_append_done (array_real); -   -  return TRUE; +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_PATH, +                                     DBUS_TYPE_OBJECT_PATH, +                                     object_path);  }  /** - * Appends a dict to the message and initializes an iterator that - * can be used to append to the dict. + * Gets the object path this message is being sent to (for + * DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted from (for + * DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none.   * - * @param iter an iterator pointing to the end of the message - * @param dict_iter pointer to an iter that will be initialized - * @returns #TRUE on success + * @param message the message + * @returns the path (should not be freed) or #NULL   */ -dbus_bool_t -dbus_message_iter_append_dict (DBusMessageIter      *iter, -			       DBusMessageIter      *dict_iter) -{ -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; -  DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter; -  int len_pos; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); -   -  if (!dbus_message_iter_append_type (real, DBUS_TYPE_DICT)) -    return FALSE;   -   -  len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t)); - -  /* Empty length for now, backfill later */ -  if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } -   -  dict_real->parent_iter = real; -  dict_real->message = real->message; -  dict_real->changed_stamp = real->message->changed_stamp; -   -  dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT; -  dict_real->pos = _dbus_string_get_length (&real->message->body); -  dict_real->end = dict_real->end; -   -  dict_real->container_start = dict_real->pos; -  dict_real->container_length_pos = len_pos; -  dict_real->wrote_dict_key = 0; - -  dbus_message_iter_append_done (dict_real); -   -  real->wrote_dict_key = FALSE; -   -  return TRUE; -} - -static dbus_bool_t -_dbus_message_iter_append_basic_array (DBusMessageIter *iter, -				       char             type, -				       const void      *value, -				       int              len) +const char* +dbus_message_get_path (DBusMessage   *message)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  const char *v; -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!append_array_type (real, type, NULL, NULL)) -    return FALSE; -   -  if (!_dbus_marshal_basic_type_array (&real->message->body, -				       type, value, len, -				       real->message->byte_order)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_val_if_fail (message != NULL, NULL); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_PATH, +                                DBUS_TYPE_OBJECT_PATH, +                                &v); +  return v;  } -  /** - * This function takes a va_list for use by language bindings. - * It's otherwise the same as dbus_message_append_args(). + * Gets the object path this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed + * format (one array element per path component). + * Free the returned array with dbus_free_string_array(). + * + * An empty but non-NULL path array means the path "/". + * So the path "/foo/bar" becomes { "foo", "bar", NULL } + * and the path "/" becomes { NULL }. + * + * @todo this could be optimized by using the len from the message + * instead of calling strlen() again   * - * @todo: Shouldn't this function clean up the changes to the message - *        on failures? (Yes) -   - * @see dbus_message_append_args.     * @param message the message - * @param first_arg_type type of first argument - * @param var_args value of first argument, then list of type/value pairs - * @returns #TRUE on success + * @param path place to store allocated array of path components; #NULL set here if no path field exists + * @returns #FALSE if no memory to allocate the array   */  dbus_bool_t -dbus_message_append_args_valist (DBusMessage *message, -				 int          first_arg_type, -				 va_list      var_args) +dbus_message_get_path_decomposed (DBusMessage   *message, +                                  char        ***path)  { -  int type, old_len; -  DBusMessageIter iter; +  const char *v;    _dbus_return_val_if_fail (message != NULL, FALSE); -   -  old_len = _dbus_string_get_length (&message->body); -   -  type = first_arg_type; +  _dbus_return_val_if_fail (path != NULL, FALSE); -  dbus_message_append_iter_init (message, &iter); -   -  while (type != DBUS_TYPE_INVALID) -    { -      switch (type) -	{ -	case DBUS_TYPE_NIL: -	  if (!dbus_message_iter_append_nil (&iter)) -	    goto errorout; -	  break; -	case DBUS_TYPE_BYTE: -	  /* Read an int from varargs, because the original unsigned -	   * char has been promoted to int. */ -	  if (!dbus_message_iter_append_byte (&iter, va_arg (var_args, int))) -	    goto errorout; -	  break; -	case DBUS_TYPE_BOOLEAN: -	  if (!dbus_message_iter_append_boolean (&iter, va_arg (var_args, dbus_bool_t))) -	    goto errorout; -	  break; -	case DBUS_TYPE_INT32: -          /* FIXME this is probably wrong, because an int passed in probably gets -           * converted to plain "int" not necessarily 32-bit. -           */ -	  if (!dbus_message_iter_append_int32 (&iter, va_arg (var_args, dbus_int32_t))) -	    goto errorout; -	  break; -	case DBUS_TYPE_UINT32: -          /* FIXME this is probably wrong, because an int passed in probably gets -           * converted to plain "int" not necessarily 32-bit. -           */ -	  if (!dbus_message_iter_append_uint32 (&iter, va_arg (var_args, dbus_uint32_t))) -	    goto errorout;	     -	  break; -#ifdef DBUS_HAVE_INT64 -        case DBUS_TYPE_INT64: -	  if (!dbus_message_iter_append_int64 (&iter, va_arg (var_args, dbus_int64_t))) -	    goto errorout; -	  break; -	case DBUS_TYPE_UINT64: -	  if (!dbus_message_iter_append_uint64 (&iter, va_arg (var_args, dbus_uint64_t))) -	    goto errorout;	     -	  break; -#endif /* DBUS_HAVE_INT64 */ -	case DBUS_TYPE_DOUBLE: -	  if (!dbus_message_iter_append_double (&iter, va_arg (var_args, double))) -	    goto errorout; -	  break; -	case DBUS_TYPE_STRING: -	  if (!dbus_message_iter_append_string (&iter, va_arg (var_args, const char *))) -	    goto errorout; -	  break; -        case DBUS_TYPE_OBJECT_PATH: -	  if (!dbus_message_iter_append_object_path (&iter, va_arg (var_args, const char*))) -	    goto errorout; -          break; -	case DBUS_TYPE_CUSTOM: -	  { -	    const char *name; -	    unsigned char *data; -	    int len; -  -	    name = va_arg (var_args, const char *); -	    data = va_arg (var_args, unsigned char *); -	    len = va_arg (var_args, int); - -	    if (!dbus_message_iter_append_custom (&iter, name, data, len)) -	      goto errorout; -	    break; -	  } -	case DBUS_TYPE_ARRAY: -	  { -	    void *data; -	    int len, type; -  -	    type = va_arg (var_args, int); -	    data = va_arg (var_args, void *); -	    len = va_arg (var_args, int); - -	    switch (type) -	      { -	      case DBUS_TYPE_BYTE: -	      case DBUS_TYPE_BOOLEAN: -	      case DBUS_TYPE_INT32: -	      case DBUS_TYPE_UINT32: -#ifdef DBUS_HAVE_INT64 -              case DBUS_TYPE_INT64: -	      case DBUS_TYPE_UINT64: -#endif /* DBUS_HAVE_INT64 */ -	      case DBUS_TYPE_DOUBLE: -		if (!_dbus_message_iter_append_basic_array (&iter, type, data, len)) -		  goto errorout; -		break; -	      case DBUS_TYPE_STRING: -		if (!dbus_message_iter_append_string_array (&iter, (const char **)data, len)) -		  goto errorout; -		break; -	      case DBUS_TYPE_OBJECT_PATH: -		if (!dbus_message_iter_append_object_path_array (&iter, (const char **)data, len)) -		  goto errorout; -		break; -	      case DBUS_TYPE_NIL: -	      case DBUS_TYPE_ARRAY: -	      case DBUS_TYPE_CUSTOM: -	      case DBUS_TYPE_DICT: -		_dbus_warn ("dbus_message_append_args_valist doesn't support recursive arrays\n"); -		goto errorout; -	      default: -		_dbus_warn ("Unknown field type %d\n", type); -		goto errorout; -	      } -	  } -	  break; -	   -	case DBUS_TYPE_DICT: -	  _dbus_warn ("dbus_message_append_args_valist doesn't support dicts\n"); -	  goto errorout; -	default: -	  _dbus_warn ("Unknown field type %d\n", type); -	  goto errorout; -	} +  *path = NULL; -      type = va_arg (var_args, int); +  v = dbus_message_get_path (message); +  if (v != NULL) +    { +      if (!_dbus_decompose_path (v, strlen (v), +                                 path, NULL)) +        return FALSE;      } -    return TRUE; - - errorout: -  return FALSE; -} - -/** - * Appends a boolean array to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_boolean_array (DBusMessageIter     *iter, -					unsigned const char *value, -					int                  len) -{ -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_BOOLEAN, -						value, len); -} - -/** - * Appends a 32 bit signed integer array to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_int32_array (DBusMessageIter    *iter, -				      const dbus_int32_t *value, -				      int                 len) -{ -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_INT32, -						value, len);  }  /** - * Appends a 32 bit unsigned integer array to the message. + * Sets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or + * the interface a signal is being emitted from + * (for DBUS_MESSAGE_TYPE_SIGNAL).   * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success + * @param message the message + * @param interface the interface or #NULL to unset + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_uint32_array (DBusMessageIter     *iter, -				       const dbus_uint32_t *value, -				       int                  len) +dbus_message_set_interface (DBusMessage  *message, +                            const char   *interface)  { -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_UINT32, -						value, len); -} - -#ifdef DBUS_HAVE_INT64 +  _dbus_return_val_if_fail (message != NULL, FALSE); +  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (interface == NULL || +                            _dbus_check_is_valid_interface (interface), +                            FALSE); -/** - * Appends a 64 bit signed integer array to the message. - * - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_int64_array (DBusMessageIter    *iter, -				      const dbus_int64_t *value, -				      int                 len) -{ -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_INT64, -						value, len); +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_INTERFACE, +                                     DBUS_TYPE_STRING, +                                     interface);  }  /** - * Appends a 64 bit unsigned integer array to the message. - * - * This function only exists if #DBUS_HAVE_INT64 is defined. + * Gets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL). + * The interface name is fully-qualified (namespaced). + * Returns #NULL if none.   * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success + * @param message the message + * @returns the message interface (should not be freed) or #NULL   */ -dbus_bool_t -dbus_message_iter_append_uint64_array (DBusMessageIter     *iter, -				       const dbus_uint64_t *value, -				       int                  len) +const char* +dbus_message_get_interface (DBusMessage *message)  { -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_UINT64, -						value, len); -} -#endif /* DBUS_HAVE_INT64 */ +  const char *v; -/** - * Appends a double array to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_double_array (DBusMessageIter *iter, -				       const double    *value, -				       int              len) -{ -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_DOUBLE, -						value, len); -} +  _dbus_return_val_if_fail (message != NULL, NULL); -/** - * Appends a byte array to the message. - * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success - */ -dbus_bool_t -dbus_message_iter_append_byte_array (DBusMessageIter     *iter, -				     unsigned const char *value, -				     int                  len) -{ -  return _dbus_message_iter_append_basic_array (iter, DBUS_TYPE_BYTE, -						value, len); +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_INTERFACE, +                                DBUS_TYPE_STRING, +                                &v); +  return v;  }  /** - * Appends a string array to the message. + * Sets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). + * The interface name is fully-qualified (namespaced).   * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success + * @param message the message + * @param member the member or #NULL to unset + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_iter_append_string_array (DBusMessageIter *iter, -				       const char     **value, -				       int              len) +dbus_message_set_member (DBusMessage  *message, +                         const char   *member)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; - -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!append_array_type (real, DBUS_TYPE_STRING, NULL, NULL)) -    return FALSE; -   -  if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_val_if_fail (message != NULL, FALSE); +  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (member == NULL || +                            _dbus_check_is_valid_member (member), +                            FALSE); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_MEMBER, +                                     DBUS_TYPE_STRING, +                                     member);  }  /** - * Appends an object path array to the message. + * Gets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none.   * - * @param iter an iterator pointing to the end of the message - * @param value the array - * @param len the length of the array - * @returns #TRUE on success + * @param message the message + * @returns the member name (should not be freed) or #NULL   */ -dbus_bool_t -dbus_message_iter_append_object_path_array (DBusMessageIter *iter, -					    const char     **value, -					    int              len) +const char* +dbus_message_get_member (DBusMessage *message)  { -  DBusMessageRealIter *real = (DBusMessageRealIter *)iter; +  const char *v; -  _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); - -  if (!append_array_type (real, DBUS_TYPE_OBJECT_PATH, NULL, NULL)) -    return FALSE; -   -  if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len)) -    { -      _dbus_string_set_length (&real->message->body, real->pos); -      return FALSE; -    } +  _dbus_return_val_if_fail (message != NULL, NULL); -  dbus_message_iter_append_done (real); -   -  return TRUE; +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_MEMBER, +                                DBUS_TYPE_STRING, +                                &v); +  return v;  }  /** - * Sets the message sender. + * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR). + * The name is fully-qualified (namespaced).   *   * @param message the message - * @param sender the sender or #NULL to unset + * @param error_name the name or #NULL to unset   * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_set_sender (DBusMessage  *message, -                         const char   *sender) +dbus_message_set_error_name (DBusMessage  *message, +                             const char   *error_name)  {    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (error_name == NULL || +                            _dbus_check_is_valid_error_name (error_name), +                            FALSE); -  return set_string_field (message, -                           DBUS_HEADER_FIELD_SENDER, -                           DBUS_TYPE_STRING, -                           sender); +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_ERROR_NAME, +                                     DBUS_TYPE_STRING, +                                     error_name);  }  /** - * Sets a flag indicating that the message does not want a reply; if - * this flag is set, the other end of the connection may (but is not - * required to) optimize by not sending method return or error - * replies. If this flag is set, there is no way to know whether the - * message successfully arrived at the remote end. + * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only) + * or #NULL if none.   *   * @param message the message - * @param no_reply #TRUE if no reply is desired + * @returns the error name (should not be freed) or #NULL   */ -void -dbus_message_set_no_reply (DBusMessage *message, -                           dbus_bool_t  no_reply) +const char* +dbus_message_get_error_name (DBusMessage *message)  { -  char *header; +  const char *v; -  _dbus_return_if_fail (message != NULL); -  _dbus_return_if_fail (!message->locked); -   -  header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1); -   -  if (no_reply) -    *header |= DBUS_HEADER_FLAG_NO_REPLY_EXPECTED; -  else -    *header &= ~DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;     +  _dbus_return_val_if_fail (message != NULL, NULL); + +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_ERROR_NAME, +                                DBUS_TYPE_STRING, +                                &v); +  return v;  }  /** - * Returns #TRUE if the message does not expect - * a reply. + * Sets the message's destination service.   *   * @param message the message - * @returns #TRUE if the message sender isn't waiting for a reply + * @param destination the destination service name or #NULL to unset + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_get_no_reply (DBusMessage *message) +dbus_message_set_destination (DBusMessage  *message, +                              const char   *destination)  { -  const char *header; -    _dbus_return_val_if_fail (message != NULL, FALSE); -   -  header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1); +  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (destination == NULL || +                            _dbus_check_is_valid_service (destination), +                            FALSE); -  return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0; +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_DESTINATION, +                                     DBUS_TYPE_STRING, +                                     destination);  } -  /** - * Sets a flag indicating that the addressed service will be auto-activated - * before the message is delivered. When this flag is set, the message is held - * until the service is succesfully activated or fail to activate. In case of - * failure, the reply will be an activation error. + * Gets the destination service of a message or #NULL if there is + * none set.   *   * @param message the message - * @param auto_activation #TRUE if auto-activation is desired + * @returns the message destination service (should not be freed) or #NULL   */ -void -dbus_message_set_auto_activation (DBusMessage *message, -				  dbus_bool_t  auto_activation) +const char* +dbus_message_get_destination (DBusMessage *message)  { -  char *header; +  const char *v; -  _dbus_return_if_fail (message != NULL); -  _dbus_return_if_fail (!message->locked); -   -  header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1); -   -  if (auto_activation) -    *header |= DBUS_HEADER_FLAG_AUTO_ACTIVATION; -  else -    *header &= ~DBUS_HEADER_FLAG_AUTO_ACTIVATION; +  _dbus_return_val_if_fail (message != NULL, NULL); + +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_DESTINATION, +                                DBUS_TYPE_STRING, +                                &v); +  return v;  }  /** - * Returns #TRUE if the message will cause the addressed service to be - * auto-activated. + * Sets the message sender.   *   * @param message the message - * @returns #TRUE if the message will use auto-activation + * @param sender the sender or #NULL to unset + * @returns #FALSE if not enough memory   */  dbus_bool_t -dbus_message_get_auto_activation (DBusMessage *message) +dbus_message_set_sender (DBusMessage  *message, +                         const char   *sender)  { -  const char *header; -    _dbus_return_val_if_fail (message != NULL, FALSE); -   -  header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1); +  _dbus_return_val_if_fail (!message->locked, FALSE); +  _dbus_return_val_if_fail (sender == NULL || +                            _dbus_check_is_valid_service (sender), +                            FALSE); -  return (*header & DBUS_HEADER_FLAG_AUTO_ACTIVATION) != 0; +  return set_or_delete_string_field (message, +                                     DBUS_HEADER_FIELD_SENDER, +                                     DBUS_TYPE_STRING, +                                     sender);  }  /** @@ -4707,11 +2620,16 @@ dbus_message_get_auto_activation (DBusMessage *message)  const char*  dbus_message_get_sender (DBusMessage *message)  { +  const char *v; +    _dbus_return_val_if_fail (message != NULL, NULL); -   -  return get_string_field (message,  -			   DBUS_HEADER_FIELD_SENDER, -			   NULL); + +  v = NULL; /* in case field doesn't exist */ +  _dbus_header_get_field_basic (&message->header, +                                DBUS_HEADER_FIELD_SENDER, +                                DBUS_TYPE_STRING, +                                &v); +  return v;  }  /** @@ -4722,49 +2640,52 @@ dbus_message_get_sender (DBusMessage *message)   * what you might expect (it does not include the signature of the   * entire C++-style method).   * - * The signature is a string made up of type codes such - * as #DBUS_TYPE_STRING. The string is terminated with nul - * (nul is also the value of #DBUS_TYPE_INVALID). - *  + * The signature is a string made up of type codes such as + * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also + * the value of #DBUS_TYPE_INVALID). + *   * @param message the message   * @returns the type signature   */  const char*  dbus_message_get_signature (DBusMessage *message)  { +  const DBusString *type_str; +  int type_pos; +    _dbus_return_val_if_fail (message != NULL, NULL); -  return get_string_field (message,  -			   DBUS_HEADER_FIELD_SIGNATURE, -			   NULL); +  get_const_signature (&message->header, &type_str, &type_pos); + +  return _dbus_string_get_const_data_len (type_str, type_pos, 0);  }  static dbus_bool_t  _dbus_message_has_type_interface_member (DBusMessage *message,                                           int          type,                                           const char  *interface, -                                         const char  *method) +                                         const char  *member)  {    const char *n;    _dbus_assert (message != NULL);    _dbus_assert (interface != NULL); -  _dbus_assert (method != NULL); +  _dbus_assert (member != NULL);    if (dbus_message_get_type (message) != type)      return FALSE; -  /* Optimize by checking the short method name first +  /* Optimize by checking the short member name first     * instead of the longer interface name -   */   +   */    n = dbus_message_get_member (message); -  if (n && strcmp (n, method) == 0) +  if (n && strcmp (n, member) == 0)      {        n = dbus_message_get_interface (message); -       -      if (n && strcmp (n, interface) == 0) + +      if (n == NULL || strcmp (n, interface) == 0)          return TRUE;      } @@ -4774,13 +2695,15 @@ _dbus_message_has_type_interface_member (DBusMessage *message,  /**   * Checks whether the message is a method call with the given   * interface and member fields.  If the message is not - * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or member field, - * returns #FALSE. + * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or + * member field, returns #FALSE. If the interface field is missing, + * then it will be assumed equal to the provided interface.  The D-BUS + * protocol allows method callers to leave out the interface name.   *   * @param message the message   * @param interface the name to check (must not be #NULL)   * @param method the name to check (must not be #NULL) - *  + *   * @returns #TRUE if the message is the specified method call   */  dbus_bool_t @@ -4791,6 +2714,9 @@ dbus_message_is_method_call (DBusMessage *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (interface != NULL, FALSE);    _dbus_return_val_if_fail (method != NULL, FALSE); +  /* don't check that interface/method are valid since it would be +   * expensive, and not catch many common errors +   */    return _dbus_message_has_type_interface_member (message,                                                    DBUS_MESSAGE_TYPE_METHOD_CALL, @@ -4798,15 +2724,16 @@ dbus_message_is_method_call (DBusMessage *message,  }  /** - * Checks whether the message is a signal with the given - * interface and member fields.  If the message is not - * #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field, - * returns #FALSE. + * Checks whether the message is a signal with the given interface and + * member fields.  If the message is not #DBUS_MESSAGE_TYPE_SIGNAL, or + * has a different interface or member field, returns #FALSE.  If the + * interface field in the message is missing, it is assumed to match + * any interface you pass in to this function.   *   * @param message the message   * @param interface the name to check (must not be #NULL)   * @param signal_name the name to check (must not be #NULL) - *  + *   * @returns #TRUE if the message is the specified signal   */  dbus_bool_t @@ -4817,6 +2744,9 @@ dbus_message_is_signal (DBusMessage *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (interface != NULL, FALSE);    _dbus_return_val_if_fail (signal_name != NULL, FALSE); +  /* don't check that interface/name are valid since it would be +   * expensive, and not catch many common errors +   */    return _dbus_message_has_type_interface_member (message,                                                    DBUS_MESSAGE_TYPE_SIGNAL, @@ -4830,7 +2760,7 @@ dbus_message_is_signal (DBusMessage *message,   *   * @param message the message   * @param error_name the name to check (must not be #NULL) - *  + *   * @returns #TRUE if the message is the specified error   */  dbus_bool_t @@ -4838,11 +2768,13 @@ dbus_message_is_error (DBusMessage *message,                         const char  *error_name)  {    const char *n; -   +    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (error_name != NULL, FALSE); -  _dbus_return_val_if_fail (is_valid_error_name (error_name), FALSE); -   +  /* don't check that error_name is valid since it would be expensive, +   * and not catch many common errors +   */ +    if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)      return FALSE; @@ -4861,7 +2793,7 @@ dbus_message_is_error (DBusMessage *message,   *   * @param message the message   * @param service the service to check (must not be #NULL) - *  + *   * @returns #TRUE if the message has the given destination service   */  dbus_bool_t @@ -4872,7 +2804,10 @@ dbus_message_has_destination (DBusMessage  *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (service != NULL, FALSE); -   +  /* don't check that service name is valid since it would be expensive, +   * and not catch many common errors +   */ +    s = dbus_message_get_destination (message);    if (s && strcmp (s, service) == 0) @@ -4890,9 +2825,12 @@ dbus_message_has_destination (DBusMessage  *message,   * function to prove the sender didn't own service Foo, you can   * only use it to prove that it did.   * + * @todo this function is probably useless unless we make a hard guarantee + * that the sender field in messages will always be the base service name + *   * @param message the message   * @param service the service to check (must not be #NULL) - *  + *   * @returns #TRUE if the message has the given origin service   */  dbus_bool_t @@ -4903,7 +2841,10 @@ dbus_message_has_sender (DBusMessage  *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (service != NULL, FALSE); -   +  /* don't check that service name is valid since it would be expensive, +   * and not catch many common errors +   */ +    s = dbus_message_get_sender (message);    if (s && strcmp (s, service) == 0) @@ -4913,9 +2854,9 @@ dbus_message_has_sender (DBusMessage  *message,  }  /** - * Checks whether the message has the given signature; - * see dbus_message_get_signature() for more details on - * what the signature looks like. + * Checks whether the message has the given signature; see + * dbus_message_get_signature() for more details on what the signature + * looks like.   *   * @param message the message   * @param signature typecode array @@ -4929,7 +2870,10 @@ dbus_message_has_signature (DBusMessage   *message,    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_fail (signature != NULL, FALSE); -   +  /* don't check that signature is valid since it would be expensive, +   * and not catch many common errors +   */ +    s = dbus_message_get_signature (message);    if (s && strcmp (s, signature) == 0) @@ -4947,9 +2891,14 @@ dbus_message_has_signature (DBusMessage   *message,   * if the argument exists and is a string.   *   * The return value indicates whether the error was set (the error is - * set if and only if the message is an error message). - * So you can check for an error reply and convert it to DBusError - * in one go. + * set if and only if the message is an error message).  So you can + * check for an error reply and convert it to DBusError in one go: + * @code + *  if (dbus_set_error_from_message (error, reply)) + *    return error; + *  else + *    process reply; + * @endcode   *   * @param error the error to set   * @param message the message to set it from @@ -4959,11 +2908,11 @@ dbus_bool_t  dbus_set_error_from_message (DBusError   *error,                               DBusMessage *message)  { -  char *str; +  const char *str;    _dbus_return_val_if_fail (message != NULL, FALSE);    _dbus_return_val_if_error_is_set (error, FALSE); -   +    if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)      return FALSE; @@ -4975,8 +2924,6 @@ dbus_set_error_from_message (DBusError   *error,    dbus_set_error (error, dbus_message_get_error_name (message),                    str ? "%s" : NULL, str); -  dbus_free (str); -      return TRUE;  } @@ -5001,18 +2948,8 @@ dbus_set_error_from_message (DBusError   *error,   * @todo write tests for break-loader that a) randomly delete header   * fields and b) set string fields to zero-length and other funky   * values. - *  - */ - -/* we definitely use signed ints for sizes, so don't exceed - * _DBUS_INT_MAX; and add 16 for paranoia, since a message - * over 128M is pretty nuts anyhow. - */ - -/** - * The maximum sane message size. + *   */ -#define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)  /**   * Implementation details of DBusMessageLoader. @@ -5023,11 +2960,11 @@ 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 */ @@ -5035,7 +2972,7 @@ struct DBusMessageLoader  /**   * The initial buffer size of the message loader. - *  + *   * @todo this should be based on min header size plus some average   * body size, or something. Or rather, the min header size only, if we   * want to try to read only the header, store that in a DBusMessage, @@ -5059,14 +2996,14 @@ _dbus_message_loader_new (void)    loader = dbus_new0 (DBusMessageLoader, 1);    if (loader == NULL)      return NULL; -   +    loader->refcount = 1;    /* Try to cap message size at something that won't *totally* hose     * the system if we have a couple of them.     */    loader->max_message_size = _DBUS_ONE_MEGABYTE * 32; -   +    if (!_dbus_string_init (&loader->data))      {        dbus_free (loader); @@ -5076,7 +3013,7 @@ _dbus_message_loader_new (void)    /* preallocate the buffer for speed, ignore failure */    _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);    _dbus_string_set_length (&loader->data, 0); -   +    return loader;  } @@ -5129,7 +3066,7 @@ _dbus_message_loader_unref (DBusMessageLoader *loader)   * or reallocs.   *   * @todo we need to enforce a max length on strings in header fields. - *  + *   * @param loader the message loader.   * @param buffer the buffer   */ @@ -5140,375 +3077,17 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,    _dbus_assert (!loader->buffer_outstanding);    *buffer = &loader->data; -   +    loader->buffer_outstanding = TRUE;  }  /** - * The smallest header size that can occur.  - * (It won't be valid) + * The smallest header size that can occur.  (It won't be valid due to + * missing required header fields.) This is 4 bytes, two uint32, an + * array length.   */  #define DBUS_MINIMUM_HEADER_SIZE 16 -static dbus_bool_t -decode_string_field (const DBusString   *data, -		     int                 field, -                     HeaderField        *header_field, -		     DBusString         *field_data, -                     int                 pos, -                     int                 type) -{ -  int string_data_pos; - -  _dbus_assert (header_field != NULL); -  _dbus_assert (field_data != NULL); -   -  if (header_field->name_offset >= 0) -    { -      _dbus_verbose ("%s field provided twice\n", -		     _dbus_header_field_to_string (field)); -      return FALSE; -    } - -  if (type != DBUS_TYPE_STRING) -    { -      _dbus_verbose ("%s field has wrong type %s\n", -                     _dbus_header_field_to_string (field), -		     _dbus_type_to_string (type)); -      return FALSE; -    } - -  /* skip padding after typecode, skip string length; -   * we assume that the string arg has already been validated -   * for sanity and UTF-8 -   */ -  string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4; -  _dbus_assert (string_data_pos < _dbus_string_get_length (data)); -   -  _dbus_string_init_const (field_data, -                           _dbus_string_get_const_data (data) + string_data_pos); - -  header_field->name_offset  = pos - 2; -  header_field->value_offset = _DBUS_ALIGN_VALUE (pos, 4); -   -#if 0 -  _dbus_verbose ("Found field %s at offset %d\n", -                 _dbus_header_field_to_string (field), -		 header_field->value_offset); -#endif - -  return TRUE; -} - -/* FIXME because the service/interface/member/error names are already - * validated to be in the particular ASCII subset, UTF-8 validating - * them could be skipped as a probably-interesting optimization. - * The UTF-8 validation shows up in callgrind-type profiles but - * not so much in sample/time-based profiles. - */ -static dbus_bool_t -decode_header_data (const DBusString   *data, -		    int		        header_len, -		    int                 byte_order, -                    int                 message_type, -                    HeaderField         fields[DBUS_HEADER_FIELD_LAST + 1], -		    int                *message_padding) -{ -  DBusString field_data; -  int pos, new_pos; -  int i; -  int field; -  int type; -  dbus_bool_t signature_required; -   -  if (header_len < 16) -    { -      _dbus_verbose ("Header length %d is too short\n", header_len); -      return FALSE; -    } -   -  i = 0; -  while (i <= DBUS_HEADER_FIELD_LAST) -    { -      fields[i].name_offset  = -1; -      fields[i].value_offset = -1; -      ++i; -    } -   -  pos = 16; -  while (pos < header_len) -    { -      field = _dbus_string_get_byte (data, pos); -      if (field == DBUS_HEADER_FIELD_INVALID) -	break; /* Must be padding */ -      pos++; - -      if (!_dbus_marshal_validate_type (data, pos, &type, &pos)) -	{ -          _dbus_verbose ("Failed to validate type of named header field pos = %d\n", -                         pos); -	  return FALSE; -	} -       -      if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos)) -        { -          _dbus_verbose ("Failed to validate argument to named header field pos = %d\n", -                         pos); -          return FALSE; -        } - -      if (new_pos > header_len) -        { -          _dbus_verbose ("Named header field tries to extend beyond header length\n"); -          return FALSE; -        } -       -      switch (field) -        { -        case DBUS_HEADER_FIELD_DESTINATION: -          if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; - -	  if (!_dbus_string_validate_service (&field_data, 0, -					      _dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("service field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -          break; - -        case DBUS_HEADER_FIELD_INTERFACE: -	  if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; - -	  if (!_dbus_string_validate_interface (&field_data, 0, -						_dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("interface field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -       -	  if (_dbus_string_equal_c_str (&field_data, -					DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL)) -	    { -	      _dbus_verbose ("Message is on the local interface\n"); -	      return FALSE; -	    } -          break; - -        case DBUS_HEADER_FIELD_MEMBER: -          if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; -	   -	  if (!_dbus_string_validate_member (&field_data, 0, -					     _dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("member field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -          break; - -        case DBUS_HEADER_FIELD_ERROR_NAME: -          if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; -	   -	  if (!_dbus_string_validate_error_name (&field_data, 0, -						 _dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("error-name field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -          break; -           -	case DBUS_HEADER_FIELD_SENDER: -          if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; -	   -	  if (!_dbus_string_validate_service (&field_data, 0, -					      _dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("sender-service field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -	  break; - -	case DBUS_HEADER_FIELD_PATH: - -          /* Path was already validated as part of standard -           * type validation, since there's an OBJECT_PATH -           * type. -           */ -           -          if (fields[field].name_offset >= 0) -            { -              _dbus_verbose ("path field provided twice\n"); -              return FALSE; -            } -          if (type != DBUS_TYPE_OBJECT_PATH) -            { -              _dbus_verbose ("path field has wrong type\n"); -              return FALSE; -            } - -          fields[field].name_offset  = pos - 2; -          fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4); - -          /* No forging signals from the local path */ -          { -            const char *s; -            s = _dbus_string_get_const_data_len (data, -                                                 fields[field].value_offset, -                                                 _dbus_string_get_length (data) - -                                                 fields[field].value_offset); -            if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0) -              { -                _dbus_verbose ("Message is on the local path\n"); -                return FALSE; -              } -          } -           -          _dbus_verbose ("Found path at offset %d\n", -                         fields[field].value_offset); -	  break; -           -	case DBUS_HEADER_FIELD_REPLY_SERIAL: -          if (fields[field].name_offset >= 0) -            { -              _dbus_verbose ("reply field provided twice\n"); -              return FALSE; -            } - -          if (type != DBUS_TYPE_UINT32) -            { -              _dbus_verbose ("reply field has wrong type\n"); -              return FALSE; -            } -           -          fields[field].name_offset  = pos - 2; -          fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4); - -          _dbus_verbose ("Found reply serial %u at offset %d\n", -                         _dbus_demarshal_uint32 (data, -                                                 byte_order, -                                                 fields[field].value_offset, -                                                 NULL), -                         fields[field].value_offset); -	  break; - -	case DBUS_HEADER_FIELD_SIGNATURE: -          if (!decode_string_field (data, field, &fields[field], -				    &field_data, pos, type)) -            return FALSE; - -	  if (!_dbus_string_validate_signature (&field_data, 0, -                                                _dbus_string_get_length (&field_data))) -	    { -	      _dbus_verbose ("signature field has invalid content \"%s\"\n", -			     _dbus_string_get_const_data (&field_data)); -	      return FALSE; -	    } -	  break; -           -        default: -	  _dbus_verbose ("Ignoring an unknown header field: %d at offset %d\n", -			 field, pos); -	} -       -      pos = new_pos; -    } - -  if (pos < header_len) -    { -      /* Alignment padding, verify that it's nul */ -      if ((header_len - pos) >= 8) -	{ -	  _dbus_verbose ("too much header alignment padding\n"); -	  return FALSE; -	} - -      if (!_dbus_string_validate_nul (data, -                                      pos, (header_len - pos))) -        { -          _dbus_verbose ("header alignment padding is not nul\n"); -          return FALSE; -        } -    } - -  /* Depending on message type, enforce presence of certain fields. */ -  signature_required = TRUE; -   -  switch (message_type) -    { -    case DBUS_MESSAGE_TYPE_SIGNAL: -    case DBUS_MESSAGE_TYPE_METHOD_CALL: -      if (fields[DBUS_HEADER_FIELD_PATH].value_offset < 0) -        { -          _dbus_verbose ("No path field provided\n"); -          return FALSE; -        } -      /* FIXME make this optional, only for method calls */ -      if (fields[DBUS_HEADER_FIELD_INTERFACE].value_offset < 0) -        { -          _dbus_verbose ("No interface field provided\n"); -          return FALSE; -        } -      if (fields[DBUS_HEADER_FIELD_MEMBER].value_offset < 0) -        { -          _dbus_verbose ("No member field provided\n"); -          return FALSE; -        } -      break; -    case DBUS_MESSAGE_TYPE_ERROR: -      if (fields[DBUS_HEADER_FIELD_ERROR_NAME].value_offset < 0) -        { -          _dbus_verbose ("No error-name field provided\n"); -          return FALSE; -        } -      if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0) -        { -          _dbus_verbose ("No reply serial field provided in error\n"); -          return FALSE; -        } -      break; -    case DBUS_MESSAGE_TYPE_METHOD_RETURN: -      if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0) -        { -          _dbus_verbose ("No reply serial field provided in method return\n"); -          return FALSE; -        } -      break; -    default: -      /* An unknown type, spec requires us to ignore it */ -      signature_required = FALSE; -      break; -    } - -  /* FIXME allow omitting signature field for a message with no arguments? */ -  if (signature_required) -    { -      if (fields[DBUS_HEADER_FIELD_SIGNATURE].value_offset < 0) -        { -          _dbus_verbose ("No signature field provided\n"); -          return FALSE; -        } -    } -   -  if (message_padding) -    *message_padding = header_len - pos;   -   -  return TRUE; -} -  /**   * Returns a buffer obtained from _dbus_message_loader_get_buffer(),   * indicating to the loader how many bytes of the buffer were filled @@ -5530,94 +3109,96 @@ _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,    loader->buffer_outstanding = FALSE;  } +/* + * FIXME when we move the header out of the buffer, that memmoves all + * buffered messages. Kind of crappy. + * + * Also we copy the header and body, which is kind of crappy.  To + * avoid this, we have to allow header and body to be in a single + * memory block, which is good for messages we read and bad for + * messages we are creating. But we could move_len() the buffer into + * this single memory block, and move_len() will just swap the buffers + * if you're moving the entire buffer replacing the dest string. + * + * We could also have the message loader tell the transport how many + * bytes to read; so it would first ask for some arbitrary number like + * 256, then if the message was incomplete it would use the + * header/body len to ask for exactly the size of the message (or + * blocks the size of a typical kernel buffer for the socket). That + * way we don't get trailing bytes in the buffer that have to be + * memmoved. Though I suppose we also don't have a chance of reading a + * bunch of small messages at once, so the optimization may be stupid. + * + * Another approach would be to keep a "start" index into + * loader->data and only delete it occasionally, instead of after + * each message is loaded. + * + * load_message() returns FALSE if not enough memory + */  static dbus_bool_t -load_one_message (DBusMessageLoader *loader, -                  int                byte_order, -                  int                message_type, -                  int                header_len, -                  int                body_len) +load_message (DBusMessageLoader *loader, +              DBusMessage       *message, +              int                byte_order, +              int                fields_array_len, +              int                header_len, +              int                body_len)  { -  DBusMessage *message; -  HeaderField fields[DBUS_HEADER_FIELD_LAST + 1]; -  int i; -  int next_arg;    dbus_bool_t oom; -  int header_padding; -   -  message = NULL; +  DBusValidity validity; +  const DBusString *type_str; +  int type_pos; +    oom = FALSE; -   +  #if 0    _dbus_verbose_bytes_of_string (&loader->data, 0, header_len /* + body_len */); -#endif	   +#endif -  if (!decode_header_data (&loader->data, -                           header_len, byte_order, -                           message_type, -                           fields, &header_padding)) -    { -      _dbus_verbose ("Header was invalid\n"); -      loader->corrupted = TRUE; +  /* 1. VALIDATE AND COPY OVER HEADER */ +  _dbus_assert (_dbus_string_get_length (&message->header.data) == 0); +  _dbus_assert ((header_len + body_len) <= _dbus_string_get_length (&loader->data)); + +  if (!_dbus_header_load_untrusted (&message->header, +                                    &validity, +                                    byte_order, +                                    fields_array_len, +                                    header_len, +                                    body_len, +                                    &loader->data, 0, +                                    _dbus_string_get_length (&loader->data))) +    { +      _dbus_verbose ("Failed to load header for new message code %d\n", validity); +      if (validity == DBUS_VALID) +        oom = TRUE;        goto failed;      } -           -  next_arg = header_len; -  while (next_arg < (header_len + body_len)) -    { -      int type; -      int prev = next_arg; -      if (!_dbus_marshal_validate_type (&loader->data, next_arg, -                                        &type, &next_arg)) -        { -          _dbus_verbose ("invalid typecode at offset %d\n", prev); -          loader->corrupted = TRUE; -          goto failed; -        } -       -      if (!_dbus_marshal_validate_arg (&loader->data, -                                       byte_order, -                                       0, -                                       type, -1, -                                       next_arg, -                                       &next_arg)) -        { -          _dbus_verbose ("invalid type data at %d, next_arg\n", next_arg); -          loader->corrupted = TRUE; -          goto failed; -        } +  _dbus_assert (validity == DBUS_VALID); -      _dbus_assert (next_arg > prev); -    } -           -  if (next_arg > (header_len + body_len)) -    { -      _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n", -                     next_arg, header_len, body_len, -                     header_len + body_len); -      loader->corrupted = TRUE; -      goto failed; -    } +  message->byte_order = byte_order; -  message = dbus_message_new_empty_header (); -  if (message == NULL) -    { -      _dbus_verbose ("Failed to allocate empty message\n"); -      oom = TRUE; +  /* 2. VALIDATE BODY */ + +  get_const_signature (&message->header, &type_str, &type_pos); + +  /* Because the bytes_remaining arg is NULL, this validates that the +   * body is the right length +   */ +  validity = _dbus_validate_body_with_reason (type_str, +                                              type_pos, +                                              byte_order, +                                              NULL, +                                              &loader->data, +                                              header_len, +                                              body_len); +  if (validity != DBUS_VALID) +    { +      _dbus_verbose ("Failed to validate message body code %d\n", validity);        goto failed;      } -  message->byte_order = byte_order; -  message->header_padding = header_padding; -	   -  /* Copy in the offsets we found */ -  i = 0; -  while (i <= DBUS_HEADER_FIELD_LAST) -    { -      message->header_fields[i] = fields[i]; -      ++i; -    } -           +  /* 3. COPY OVER BODY AND QUEUE MESSAGE */ +    if (!_dbus_list_append (&loader->messages, message))      {        _dbus_verbose ("Failed to append new message to loader queue\n"); @@ -5625,51 +3206,22 @@ load_one_message (DBusMessageLoader *loader,        goto failed;      } -  _dbus_assert (_dbus_string_get_length (&message->header) == 0);    _dbus_assert (_dbus_string_get_length (&message->body) == 0); -    _dbus_assert (_dbus_string_get_length (&loader->data) >=                  (header_len + body_len)); -           -  if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0)) -    { -      _dbus_verbose ("Failed to move header into new message\n"); -      oom = TRUE; -      goto failed; -    } -           -  if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0)) + +  if (!_dbus_string_copy_len (&loader->data, header_len, body_len, &message->body, 0))      {        _dbus_verbose ("Failed to move body into new message\n"); -              oom = TRUE;        goto failed;      } -  _dbus_assert (_dbus_string_get_length (&message->header) == header_len); +  _dbus_string_delete (&loader->data, 0, header_len + body_len); + +  _dbus_assert (_dbus_string_get_length (&message->header.data) == header_len);    _dbus_assert (_dbus_string_get_length (&message->body) == body_len); -  /* Fill in caches (we checked the types of these fields -   * earlier) -   */ -  message->reply_serial = get_uint_field (message, -                                          DBUS_HEADER_FIELD_REPLY_SERIAL); -   -  message->client_serial = _dbus_demarshal_uint32 (&message->header, -                                                   message->byte_order, -                                                   CLIENT_SERIAL_OFFSET, -                                                   NULL); -  if (message->client_serial == 0 || -      (message->header_fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset >= 0 && message->reply_serial == 0)) -    { -      _dbus_verbose ("client_serial = %d reply_serial = %d, one of these no good\n", -                     message->client_serial, -                     message->reply_serial); -       -      loader->corrupted = TRUE; -      goto failed; -    } -      _dbus_verbose ("Loaded message %p\n", message);    _dbus_assert (!oom); @@ -5678,153 +3230,76 @@ load_one_message (DBusMessageLoader *loader,    return TRUE;   failed: -   +    /* Clean up */ -   -  if (message != NULL) -    { -      /* Put the data back so we can try again later if it was an OOM issue */ -      if (_dbus_string_get_length (&message->body) > 0) -        { -          dbus_bool_t result; -           -          result = _dbus_string_copy_len (&message->body, 0, body_len, -                                          &loader->data, 0); -           -          _dbus_assert (result); /* because DBusString never reallocs smaller */ -        } -       -      if (_dbus_string_get_length (&message->header) > 0) -        { -          dbus_bool_t result; -           -          result = _dbus_string_copy_len (&message->header, 0, header_len, -                                          &loader->data, 0); -           -          _dbus_assert (result); /* because DBusString never reallocs smaller */ -        } -      /* does nothing if the message isn't in the list */ -      _dbus_list_remove_last (&loader->messages, message); +  /* does nothing if the message isn't in the list */ +  _dbus_list_remove_last (&loader->messages, message); -      dbus_message_unref (message); -    } +  if (!oom) +    loader->corrupted = TRUE; + +  _dbus_verbose_bytes_of_string (&loader->data, 0, _dbus_string_get_length (&loader->data)); -      return !oom;  }  /** - * Converts buffered data into messages. + * Converts buffered data into messages, if we have enough data.  If + * we don't have enough data, does nothing.   *   * @todo we need to check that the proper named header fields exist   * for each message type. - *  + *   * @todo If a message has unknown type, we should probably eat it   * right here rather than passing it out to applications.  However   * it's not an error to see messages of unknown type. - *  + *   * @param loader the loader.   * @returns #TRUE if we had enough memory to finish.   */  dbus_bool_t  _dbus_message_loader_queue_messages (DBusMessageLoader *loader)  { -  while (!loader->corrupted && _dbus_string_get_length (&loader->data) >= 16) +  while (!loader->corrupted && +         _dbus_string_get_length (&loader->data) >= DBUS_MINIMUM_HEADER_SIZE)      { -      const char *header_data; -      int byte_order, message_type, header_len, body_len; -      dbus_uint32_t header_len_unsigned, body_len_unsigned; -       -      header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16); - -      _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data); - -      if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION) -        { -          _dbus_verbose ("Message has protocol version %d ours is %d\n", -                         (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION); -          loader->corrupted = TRUE; -          return TRUE; -        } -       -      byte_order = header_data[BYTE_ORDER_OFFSET]; +      DBusValidity validity; +      int byte_order, fields_array_len, header_len, body_len; -      if (byte_order != DBUS_LITTLE_ENDIAN && -	  byte_order != DBUS_BIG_ENDIAN) -	{ -          _dbus_verbose ("Message with bad byte order '%c' received\n", -                         byte_order); -	  loader->corrupted = TRUE; -	  return TRUE; -	} - -      /* Unknown types are ignored, but INVALID is -       * disallowed -       */ -      message_type = header_data[TYPE_OFFSET]; -      if (message_type == DBUS_MESSAGE_TYPE_INVALID) -        { -          _dbus_verbose ("Message with bad type '%d' received\n", -                         message_type); -	  loader->corrupted = TRUE; -	  return TRUE; -        }       -       -      header_len_unsigned = _dbus_unpack_uint32 (byte_order,  -                                                 (const unsigned char *) header_data + 4); -      body_len_unsigned = _dbus_unpack_uint32 (byte_order,  -                                               (const unsigned char *) header_data + 8); - -      if (header_len_unsigned < 16) +      if (_dbus_header_have_message_untrusted (loader->max_message_size, +                                               &validity, +                                               &byte_order, +                                               &fields_array_len, +                                               &header_len, +                                               &body_len, +                                               &loader->data, 0, +                                               _dbus_string_get_length (&loader->data)))          { -          _dbus_verbose ("Message had broken too-small header length %u\n", -                         header_len_unsigned); -          loader->corrupted = TRUE; -          return TRUE; -        } +          DBusMessage *message; -      if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE || -          body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE) -        { -          _dbus_verbose ("Header or body length too large (%u %u)\n", -                         header_len_unsigned, -                         body_len_unsigned); -          loader->corrupted = TRUE; -          return TRUE; -        } +          _dbus_assert (validity == DBUS_VALID); -      /* Now that we know the values are in signed range, get -       * rid of stupid unsigned, just causes bugs -       */ -      header_len = header_len_unsigned; -      body_len = body_len_unsigned; +          message = dbus_message_new_empty_header (); +          if (message == NULL) +            return FALSE; -      if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned) +          if (!load_message (loader, message, +                             byte_order, fields_array_len, +                             header_len, body_len)) +            { +              dbus_message_unref (message); +              return FALSE; +            } +	} +      else          { -	   -          _dbus_verbose ("header length %d is not aligned to 8 bytes\n", -                         header_len); -          loader->corrupted = TRUE; +          _dbus_verbose ("Initial peek at header says we don't have a whole message yet, or data broken with invalid code %d\n", +                         validity); +          if (validity != DBUS_VALID) +            loader->corrupted = TRUE;            return TRUE;          } -       -      if (header_len + body_len > loader->max_message_size) -	{ -          _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %ld\n", -                         header_len, body_len, loader->max_message_size); -	  loader->corrupted = TRUE; -	  return TRUE; -	} - -      if (_dbus_string_get_length (&loader->data) >= (header_len + body_len)) -	{ -          if (!load_one_message (loader, byte_order, message_type, -                                 header_len, body_len)) -            return FALSE; -	} -      else -        return TRUE;      }    return TRUE; @@ -5912,11 +3387,11 @@ void  _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,                                             long                size)  { -  if (size > MAX_SANE_MESSAGE_SIZE) +  if (size > DBUS_MAXIMUM_MESSAGE_LENGTH)      {        _dbus_verbose ("clamping requested max message size %ld to %d\n", -                     size, MAX_SANE_MESSAGE_SIZE); -      size = MAX_SANE_MESSAGE_SIZE; +                     size, DBUS_MAXIMUM_MESSAGE_LENGTH); +      size = DBUS_MAXIMUM_MESSAGE_LENGTH;      }    loader->max_message_size = size;  } @@ -5943,7 +3418,7 @@ _DBUS_DEFINE_GLOBAL_LOCK (message_slots);   * The passed-in slot must be initialized to -1, and is filled in   * with the slot ID. If the passed-in slot is not -1, it's assumed   * to be already allocated, and its refcount is incremented. - *  + *   * The allocated slot is global, i.e. all DBusMessage objects will   * have a slot with the given integer ID reserved.   * @@ -5973,7 +3448,7 @@ void  dbus_message_free_data_slot (dbus_int32_t *slot_p)  {    _dbus_return_if_fail (*slot_p >= 0); -   +    _dbus_data_slot_allocator_free (&slot_allocator, slot_p);  } @@ -6033,7 +3508,7 @@ dbus_message_get_data (DBusMessage   *message,    void *res;    _dbus_return_val_if_fail (message != NULL, NULL); -   +    res = _dbus_data_slot_list_get (&slot_allocator,                                    &message->slot_list,                                    slot); @@ -6052,7 +3527,7 @@ dbus_message_get_data (DBusMessage   *message,   *   "error"          -> DBUS_MESSAGE_TYPE_ERROR   *   anything else    -> DBUS_MESSAGE_TYPE_INVALID   * @endcode - *  + *   */  int  dbus_message_type_from_string (const char *type_str) @@ -6080,7 +3555,7 @@ dbus_message_type_from_string (const char *type_str)   *   DBUS_MESSAGE_TYPE_ERROR          -> "error"   *   DBUS_MESSAGE_TYPE_INVALID        -> "invalid"   * @endcode - *  + *   */  const char *  dbus_message_type_to_string (int type) @@ -6106,439 +3581,6 @@ dbus_message_type_to_string (int type)  #include <stdio.h>  #include <stdlib.h> -static void -message_iter_test (DBusMessage *message) -{ -  DBusMessageIter iter, dict, dict2, array, array2; -  char *str; -  unsigned char *data; -  dbus_int32_t *our_int_array; -  int len; -   -  dbus_message_iter_init (message, &iter); - -  /* String tests */ -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) -    _dbus_assert_not_reached ("Argument type isn't string"); - -  str = dbus_message_iter_get_string (&iter); -  if (strcmp (str, "Test string") != 0) -    _dbus_assert_not_reached ("Strings differ"); -  dbus_free (str); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  /* Signed integer tests */ -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Argument type isn't int32"); - -  if (dbus_message_iter_get_int32 (&iter) != -0x12345678) -    _dbus_assert_not_reached ("Signed integers differ"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of fields"); -   -  /* Unsigned integer tests */ -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32) -    _dbus_assert_not_reached ("Argument type isn't int32"); - -  if (dbus_message_iter_get_uint32 (&iter) != 0xedd1e) -    _dbus_assert_not_reached ("Unsigned integers differ"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  /* Double tests */ -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DOUBLE) -    _dbus_assert_not_reached ("Argument type isn't double"); - -  if (dbus_message_iter_get_double (&iter) != 3.14159) -    _dbus_assert_not_reached ("Doubles differ"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  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_array_type (&iter) != DBUS_TYPE_DOUBLE) -    _dbus_assert_not_reached ("Array type not double"); - -   -  dbus_message_iter_init_array_iterator (&iter, &array, NULL); - -  if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE) -    _dbus_assert_not_reached ("Argument type isn't double"); - -  if (dbus_message_iter_get_double (&array) != 1.5) -    _dbus_assert_not_reached ("Unsigned integers differ"); - -  if (!dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE) -    _dbus_assert_not_reached ("Argument type isn't double"); - -  if (dbus_message_iter_get_double (&array) != 2.5) -    _dbus_assert_not_reached ("Unsigned integers differ"); - -  if (dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Didn't reach end of arguments"); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); -   - -  /* dict */ - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT) -    _dbus_assert_not_reached ("not dict type"); -      -  dbus_message_iter_init_dict_iterator (&iter, &dict); - -  str = dbus_message_iter_get_dict_key (&dict); -  if (str == NULL || strcmp (str, "test") != 0) -    _dbus_assert_not_reached ("wrong dict key"); -  dbus_free (str); - -  if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32) -    _dbus_assert_not_reached ("wrong dict entry type"); - -  if (dbus_message_iter_get_uint32 (&dict) != 0xDEADBEEF) -    _dbus_assert_not_reached ("wrong dict entry value"); - -  /* dict (in dict) */ - -  if (!dbus_message_iter_next (&dict)) -    _dbus_assert_not_reached ("reached end of dict"); -   -  if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_DICT) -    _dbus_assert_not_reached ("not dict type"); -     -  dbus_message_iter_init_dict_iterator (&dict, &dict2); -   -  str = dbus_message_iter_get_dict_key (&dict2); -  if (str == NULL || strcmp (str, "dictkey") != 0) -    _dbus_assert_not_reached ("wrong dict key"); -  dbus_free (str); -   -  if (dbus_message_iter_get_arg_type (&dict2) != DBUS_TYPE_STRING) -    _dbus_assert_not_reached ("wrong dict entry type"); -   -  str = dbus_message_iter_get_string (&dict2); -  if (str == NULL || strcmp (str, "dictvalue") != 0) -    _dbus_assert_not_reached ("wrong dict entry value"); -  dbus_free (str); -   -  if (dbus_message_iter_next (&dict2)) -    _dbus_assert_not_reached ("didn't reach end of dict"); - -  if (!dbus_message_iter_next (&dict)) -    _dbus_assert_not_reached ("reached end of dict"); -   -  /* array of array of int32 (in dict) */ - -  str = dbus_message_iter_get_dict_key (&dict); -  if (str == NULL || strcmp (str, "array") != 0) -    _dbus_assert_not_reached ("wrong dict key"); -  dbus_free (str); -   -  if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("Argument type not an array"); - -  if (dbus_message_iter_get_array_type (&dict) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("Array type not array"); - -  dbus_message_iter_init_array_iterator (&dict, &array, NULL); - -  if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("Argument type isn't array"); -   -  if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Array type not int32"); -   -  dbus_message_iter_init_array_iterator (&array, &array2, NULL); - -  if (dbus_message_iter_get_arg_type (&array2) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Argument type isn't int32"); - -  if (dbus_message_iter_get_int32 (&array2) != 0x12345678) -    _dbus_assert_not_reached ("Signed integers differ"); - -  if (!dbus_message_iter_next (&array2)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_int32 (&array2) != 0x23456781) -    _dbus_assert_not_reached ("Signed integers differ"); - -  if (dbus_message_iter_next (&array2)) -    _dbus_assert_not_reached ("Didn't reached end of arguments"); - -  if (!dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Array type not int32"); - -  if (!dbus_message_iter_get_int32_array (&array, -					  &our_int_array, -					  &len)) -    _dbus_assert_not_reached ("couldn't get int32 array"); - -  _dbus_assert (len == 3); -  _dbus_assert (our_int_array[0] == 0x34567812 && -		our_int_array[1] == 0x45678123 && -		our_int_array[2] == 0x56781234); -  dbus_free (our_int_array); -   -  if (dbus_message_iter_next (&array)) -    _dbus_assert_not_reached ("Didn't reach end of array"); - -  if (dbus_message_iter_next (&dict)) -    _dbus_assert_not_reached ("Didn't reach end of dict"); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); -   -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_BYTE) -    { -      _dbus_warn ("type was: %d\n", dbus_message_iter_get_arg_type (&iter)); -      _dbus_assert_not_reached ("wrong type after dict (should be byte)"); -    } -   -  if (dbus_message_iter_get_byte (&iter) != 0xF0) -    _dbus_assert_not_reached ("wrong value after dict"); - - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); -   -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NIL) -    _dbus_assert_not_reached ("not a nil type"); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); -   -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_CUSTOM) -    _dbus_assert_not_reached ("wrong type after dict"); - -  if (!dbus_message_iter_get_custom (&iter, &str, &data, &len)) -    _dbus_assert_not_reached ("failed to get custom type"); - -  _dbus_assert (strcmp (str, "MyTypeName")==0); -  _dbus_assert (len == 5); -  _dbus_assert (strcmp (data, "data")==0); -  dbus_free (str); -  dbus_free (data); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_byte (&iter) != 0xF0) -    _dbus_assert_not_reached ("wrong value after custom"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) -    _dbus_assert_not_reached ("no array"); - -  if (dbus_message_iter_get_array_type (&iter) != DBUS_TYPE_INT32) -    _dbus_assert_not_reached ("Array type not int32"); - -  if (dbus_message_iter_init_array_iterator (&iter, &array, NULL)) -    _dbus_assert_not_reached ("non empty array"); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_byte (&iter) != 0xF0) -    _dbus_assert_not_reached ("wrong value after empty array"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT) -    _dbus_assert_not_reached ("non dict"); - -  if (dbus_message_iter_init_dict_iterator (&iter, &dict)) -    _dbus_assert_not_reached ("non empty dict"); - -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); - -  if (dbus_message_iter_get_byte (&iter) != 0xF0) -    _dbus_assert_not_reached ("wrong value after empty dict"); - -  if (dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Didn't reach end of arguments"); -} - - -static dbus_bool_t -check_message_handling_type (DBusMessageIter *iter, -			     int type) -{ -  DBusMessageIter child_iter; -   -  switch (type) -    { -    case DBUS_TYPE_NIL: -      break; -    case DBUS_TYPE_BYTE: -      dbus_message_iter_get_byte (iter); -      break; -    case DBUS_TYPE_BOOLEAN: -      dbus_message_iter_get_boolean (iter); -      break; -    case DBUS_TYPE_INT32: -      dbus_message_iter_get_int32 (iter); -      break; -    case DBUS_TYPE_UINT32: -      dbus_message_iter_get_uint32 (iter); -      break; -    case DBUS_TYPE_INT64: -#ifdef DBUS_HAVE_INT64 -      dbus_message_iter_get_int64 (iter); -#endif -      break; -    case DBUS_TYPE_UINT64: -#ifdef DBUS_HAVE_INT64 -      dbus_message_iter_get_uint64 (iter); -#endif -      break; -    case DBUS_TYPE_DOUBLE: -      dbus_message_iter_get_double (iter); -      break; -    case DBUS_TYPE_STRING: -      { -	char *str; -	str = dbus_message_iter_get_string (iter); -	if (str == NULL) -	  { -	    _dbus_warn ("NULL string in message\n"); -	    return FALSE; -	  } -	dbus_free (str); -      } -      break; -    case DBUS_TYPE_CUSTOM: -      { -	char *name; -	unsigned char *data; -	int len; -	 -	if (!dbus_message_iter_get_custom (iter, &name, &data, &len)) -	  { -	    _dbus_warn ("error reading name from custom type\n"); -	    return FALSE; -	  } -	dbus_free (data); -	dbus_free (name); -      } -      break; -    case DBUS_TYPE_ARRAY: -      { -	int array_type; - -	dbus_message_iter_init_array_iterator (iter, &child_iter, &array_type); - -	while (dbus_message_iter_has_next (&child_iter)) -	  { -	    if (!check_message_handling_type (&child_iter, array_type)) -	      { -		_dbus_warn ("error in array element\n"); -		return FALSE; -	      } -	     -	    if (!dbus_message_iter_next (&child_iter)) -	      break; -	  } -      } -      break; -    case DBUS_TYPE_DICT: -      { -	int entry_type; -	char *key; -	 -	dbus_message_iter_init_dict_iterator (iter, &child_iter); - -	while ((entry_type = dbus_message_iter_get_arg_type (&child_iter)) != DBUS_TYPE_INVALID) -	  { -	    key = dbus_message_iter_get_dict_key (&child_iter); -	    if (key == NULL) -	      { -		_dbus_warn ("error reading dict key\n"); -		return FALSE; -	      } -	    dbus_free (key); -	     -	    if (!check_message_handling_type (&child_iter, entry_type)) -	      { -		_dbus_warn ("error in dict value\n"); -		return FALSE; -	      } -	     -	    if (!dbus_message_iter_next (&child_iter)) -	      break; -	  } -      } -      break; -       -    default: -      _dbus_warn ("unknown type %d\n", type); -      return FALSE; -      break; -    } -  return TRUE; -} -   -   -static dbus_bool_t -check_message_handling (DBusMessage *message) -{ -  DBusMessageIter iter; -  int type; -  dbus_bool_t retval; -  dbus_uint32_t client_serial; -   -  retval = FALSE; -   -  client_serial = dbus_message_get_serial (message); - -  /* can't use set_serial due to the assertions at the start of it */ -  _dbus_marshal_set_uint32 (&message->header, -                            message->byte_order, -                            CLIENT_SERIAL_OFFSET, -                            client_serial); -   -  if (client_serial != dbus_message_get_serial (message)) -    { -      _dbus_warn ("get/set cycle for client_serial did not succeed\n"); -      goto failed; -    } -   -  /* If we implement message_set_arg (message, n, value) -   * then we would want to test it here -   */ - -  dbus_message_iter_init (message, &iter); -  while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) -    { -      if (!check_message_handling_type (&iter, type)) -	goto failed; - -      if (!dbus_message_iter_next (&iter)) -        break; -    } -   -  retval = TRUE; -   - failed: -  return retval; -} -  static dbus_bool_t  check_have_valid_message (DBusMessageLoader *loader)  { @@ -6550,33 +3592,36 @@ check_have_valid_message (DBusMessageLoader *loader)    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;   -   +    goto failed; +#endif +    retval = TRUE;   failed: @@ -6595,7 +3640,7 @@ check_invalid_message (DBusMessageLoader *loader)    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"); @@ -6619,13 +3664,13 @@ check_incomplete_message (DBusMessageLoader *loader)    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)      { @@ -6647,7 +3692,7 @@ check_loader_results (DBusMessageLoader      *loader,  {    if (!_dbus_message_loader_queue_messages (loader))      _dbus_assert_not_reached ("no memory to queue messages"); -   +    switch (validity)      {      case _DBUS_MESSAGE_VALID: @@ -6680,7 +3725,7 @@ dbus_internal_do_not_use_load_message_file (const DBusString    *filename,  {    dbus_bool_t retval; -  retval = FALSE;   +  retval = FALSE;    if (is_raw)      { @@ -6699,7 +3744,9 @@ dbus_internal_do_not_use_load_message_file (const DBusString    *filename,      }    else      { -      if (!_dbus_message_data_load (data, filename)) +      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)); @@ -6708,7 +3755,7 @@ dbus_internal_do_not_use_load_message_file (const DBusString    *filename,      }    retval = TRUE; -   +   failed:    return retval; @@ -6732,7 +3779,7 @@ dbus_internal_do_not_use_try_message_file (const DBusString    *filename,    dbus_bool_t retval;    retval = FALSE; -   +    if (!_dbus_string_init (&data))      _dbus_assert_not_reached ("could not allocate string\n"); @@ -6749,11 +3796,11 @@ dbus_internal_do_not_use_try_message_file (const DBusString    *filename,        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; @@ -6780,14 +3827,14 @@ dbus_internal_do_not_use_try_message_data (const DBusString    *data,    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++)      { @@ -6798,7 +3845,7 @@ dbus_internal_do_not_use_try_message_data (const DBusString    *data,                                  _dbus_string_get_byte (data, i));        _dbus_message_loader_return_buffer (loader, buffer, 1);      } -   +    if (!check_loader_results (loader, expected_validity))      goto failed; @@ -6806,26 +3853,26 @@ dbus_internal_do_not_use_try_message_data (const DBusString    *data,    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;   +  loader = NULL;    /* Write the data 2 bytes at a time */ -   +    loader = _dbus_message_loader_new ();    len = _dbus_string_get_length (data); @@ -6841,20 +3888,20 @@ dbus_internal_do_not_use_try_message_data (const DBusString    *data,                                    _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;  } @@ -6873,17 +3920,17 @@ process_test_subdir (const DBusString          *test_base_dir,    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))     + +  if (!_dbus_concat_dir_and_file (&test_directory, &filename))      _dbus_assert_not_reached ("couldn't allocate full path");    _dbus_string_free (&filename); @@ -6902,13 +3949,13 @@ process_test_subdir (const DBusString          *test_base_dir,      }    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"); @@ -6932,13 +3979,13 @@ process_test_subdir (const DBusString          *test_base_dir,        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); @@ -6956,9 +4003,9 @@ process_test_subdir (const DBusString          *test_base_dir,        dbus_error_free (&error);        goto failed;      } -     +    retval = TRUE; -   +   failed:    if (dir) @@ -6968,7 +4015,7 @@ process_test_subdir (const DBusString          *test_base_dir,    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. @@ -6987,7 +4034,7 @@ dbus_internal_do_not_use_foreach_message_file (const char                *test_d    dbus_bool_t retval;    retval = FALSE; -   +    _dbus_string_init_const (&test_directory, test_data_dir);    if (!process_test_subdir (&test_directory, "valid-messages", @@ -6997,52 +4044,147 @@ dbus_internal_do_not_use_foreach_message_file (const char                *test_d    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_array_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_array_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, dict; +  DBusMessageIter iter;    DBusError error;    dbus_int32_t our_int; -  char *our_str; +  const char *our_str;    double our_double; -  dbus_bool_t our_bool; +  unsigned char our_bool;    unsigned char our_byte_1, our_byte_2;    dbus_uint32_t our_uint32; -  dbus_int32_t *our_uint32_array; +  const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef;    int our_uint32_array_len; -  dbus_int32_t *our_int32_array; +  dbus_int32_t *our_int32_array = (void*)0xdeadbeef;    int our_int32_array_len; -  char **our_string_array; -  int our_string_array_len;  #ifdef DBUS_HAVE_INT64    dbus_int64_t our_int64;    dbus_uint64_t our_uint64; -  dbus_int64_t *our_uint64_array; +  dbus_int64_t *our_uint64_array = (void*)0xdeadbeef;    int our_uint64_array_len; -  dbus_int64_t *our_int64_array; +  const dbus_int64_t *our_int64_array = (void*)0xdeadbeef;    int our_int64_array_len;  #endif -  double *our_double_array; +  const double *our_double_array = (void*)0xdeadbeef;    int our_double_array_len; -  unsigned char *our_byte_array; +  const unsigned char *our_byte_array = (void*)0xdeadbeef;    int our_byte_array_len; -  unsigned char *our_boolean_array; +  const unsigned char *our_boolean_array = (void*)0xdeadbeef;    int our_boolean_array_len; -   +    dbus_message_iter_init (message, &iter);    dbus_error_init (&error); @@ -7057,7 +4199,6 @@ verify_test_message (DBusMessage *message)  				   DBUS_TYPE_BOOLEAN, &our_bool,  				   DBUS_TYPE_BYTE, &our_byte_1,  				   DBUS_TYPE_BYTE, &our_byte_2, -				   DBUS_TYPE_NIL,  				   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,                                     &our_uint32_array, &our_uint32_array_len,                                     DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, @@ -7068,8 +4209,6 @@ verify_test_message (DBusMessage *message)                                     DBUS_TYPE_ARRAY, DBUS_TYPE_INT64,                                     &our_int64_array, &our_int64_array_len,  #endif -                                   DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -                                   &our_string_array, &our_string_array_len,                                     DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE,                                     &our_double_array, &our_double_array_len,                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, @@ -7092,13 +4231,12 @@ verify_test_message (DBusMessage *message)    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!"); -  dbus_free (our_str);    if (!our_bool)      _dbus_assert_not_reached ("booleans differ"); @@ -7115,7 +4253,6 @@ verify_test_message (DBusMessage *message)        our_uint32_array[2] != 0x34567812 ||        our_uint32_array[3] != 0x45678123)      _dbus_assert_not_reached ("uint array differs"); -  dbus_free (our_uint32_array);    if (our_int32_array_len != 4 ||        our_int32_array[0] != 0x12345678 || @@ -7123,7 +4260,6 @@ verify_test_message (DBusMessage *message)        our_int32_array[2] != 0x34567812 ||        our_int32_array[3] != -0x45678123)      _dbus_assert_not_reached ("int array differs"); -  dbus_free (our_int32_array);  #ifdef DBUS_HAVE_INT64    if (our_uint64_array_len != 4 || @@ -7132,27 +4268,14 @@ verify_test_message (DBusMessage *message)        our_uint64_array[2] != 0x34567812 ||        our_uint64_array[3] != 0x45678123)      _dbus_assert_not_reached ("uint64 array differs"); -  dbus_free (our_uint64_array); -   +    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"); -  dbus_free (our_int64_array);  #endif /* DBUS_HAVE_INT64 */ -   -  if (our_string_array_len != 4) -    _dbus_assert_not_reached ("string array has wrong length"); - -  if (strcmp (our_string_array[0], "Foo") != 0 || -      strcmp (our_string_array[1], "bar") != 0 || -      strcmp (our_string_array[2], "") != 0 || -      strcmp (our_string_array[3], "woo woo woo woo") != 0) -    _dbus_assert_not_reached ("string array differs"); - -  dbus_free_string_array (our_string_array);    if (our_double_array_len != 3)      _dbus_assert_not_reached ("double array had wrong length"); @@ -7165,8 +4288,6 @@ verify_test_message (DBusMessage *message)        our_double_array[2] != -300.0)      _dbus_assert_not_reached ("double array had wrong values"); -  dbus_free (our_double_array); -    if (our_byte_array_len != 4)      _dbus_assert_not_reached ("byte array had wrong length"); @@ -7176,8 +4297,6 @@ verify_test_message (DBusMessage *message)        our_byte_array[3] != 234)      _dbus_assert_not_reached ("byte array had wrong values"); -  dbus_free (our_byte_array); -    if (our_boolean_array_len != 5)      _dbus_assert_not_reached ("bool array had wrong length"); @@ -7188,42 +4307,6 @@ verify_test_message (DBusMessage *message)        our_boolean_array[4] != FALSE)      _dbus_assert_not_reached ("bool array had wrong values"); -  dbus_free (our_boolean_array); - -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT) -    _dbus_assert_not_reached ("not dict type"); -      -  dbus_message_iter_init_dict_iterator (&iter, &dict); - -  our_str = dbus_message_iter_get_dict_key (&dict); -  if (our_str == NULL || strcmp (our_str, "test") != 0) -    _dbus_assert_not_reached ("wrong dict key"); -  dbus_free (our_str); - -  if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32) -    { -      _dbus_verbose ("dict entry type: %d\n", dbus_message_iter_get_arg_type (&dict)); -      _dbus_assert_not_reached ("wrong dict entry type"); -    } - -  if ((our_uint32 = dbus_message_iter_get_uint32 (&dict)) != 0xDEADBEEF) -    { -      _dbus_verbose ("dict entry val: %x\n", our_uint32); -      _dbus_assert_not_reached ("wrong dict entry value"); -    } - -  if (dbus_message_iter_next (&dict)) -    _dbus_assert_not_reached ("Didn't reach end of dict"); -   -  if (!dbus_message_iter_next (&iter)) -    _dbus_assert_not_reached ("Reached end of arguments"); -   -  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32) -    _dbus_assert_not_reached ("wrong type after dict"); -   -  if (dbus_message_iter_get_uint32 (&iter) != 0xCAFEBABE) -    _dbus_assert_not_reached ("wrong value after dict"); -    if (dbus_message_iter_next (&iter))      _dbus_assert_not_reached ("Didn't reach end of arguments");  } @@ -7249,21 +4332,40 @@ _dbus_message_test (const char *test_data_dir)      { 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", @@ -7276,13 +4378,29 @@ _dbus_message_test (const char *test_data_dir)    _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); @@ -7295,7 +4413,7 @@ _dbus_message_test (const char *test_data_dir)    _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), @@ -7305,7 +4423,7 @@ _dbus_message_test (const char *test_data_dir)      _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), @@ -7321,14 +4439,14 @@ _dbus_message_test (const char *test_data_dir)      _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), @@ -7338,57 +4456,60 @@ _dbus_message_test (const char *test_data_dir)      _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, -0x12345678, +			    DBUS_TYPE_INT32, &v_INT32,  #ifdef DBUS_HAVE_INT64 -                            DBUS_TYPE_INT64, DBUS_INT64_CONSTANT (-0x123456789abcd), -                            DBUS_TYPE_UINT64, DBUS_UINT64_CONSTANT (0x123456789abcd), +                            DBUS_TYPE_INT64, &v_INT64, +                            DBUS_TYPE_UINT64, &v_UINT64,  #endif -			    DBUS_TYPE_STRING, "Test string", -			    DBUS_TYPE_DOUBLE, 3.14159, -			    DBUS_TYPE_BOOLEAN, TRUE, -			    DBUS_TYPE_BYTE, (unsigned char) 42, -			    DBUS_TYPE_BYTE, 24, -			    DBUS_TYPE_NIL, -			    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, our_uint32_array, +			    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, our_int32_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, our_uint64_array, +                            DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64,                              _DBUS_N_ELEMENTS (our_uint64_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array, +                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64,                              _DBUS_N_ELEMENTS (our_int64_array),  #endif -                            DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array, -                            _DBUS_N_ELEMENTS (our_string_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array, +                            DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE,                              _DBUS_N_ELEMENTS (our_double_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, our_byte_array, +                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE,                              _DBUS_N_ELEMENTS (our_byte_array), -                            DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, our_boolean_array, +                            DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN,                              _DBUS_N_ELEMENTS (our_boolean_array), -			    0); -   -  dbus_message_append_iter_init (message, &iter); -  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); -  dbus_message_iter_append_uint32 (&iter, 0xCAFEBABE); +			    DBUS_TYPE_INVALID);    i = 0;    sig[i++] = DBUS_TYPE_INT32; @@ -7401,7 +4522,6 @@ _dbus_message_test (const char *test_data_dir)    sig[i++] = DBUS_TYPE_BOOLEAN;    sig[i++] = DBUS_TYPE_BYTE;    sig[i++] = DBUS_TYPE_BYTE; -  sig[i++] = DBUS_TYPE_NIL;    sig[i++] = DBUS_TYPE_ARRAY;    sig[i++] = DBUS_TYPE_UINT32;    sig[i++] = DBUS_TYPE_ARRAY; @@ -7413,46 +4533,44 @@ _dbus_message_test (const char *test_data_dir)    sig[i++] = DBUS_TYPE_INT64;  #endif    sig[i++] = DBUS_TYPE_ARRAY; -  sig[i++] = DBUS_TYPE_STRING; -  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_DICT; -  sig[i++] = DBUS_TYPE_UINT32;    sig[i++] = DBUS_TYPE_INVALID;    _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); -   -  _dbus_verbose_bytes_of_string (&message->header, 0, -                                 _dbus_string_get_length (&message->header)); + +  _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 (message->client_serial == copy->client_serial); -  _dbus_assert (message->reply_serial == copy->reply_serial); -  _dbus_assert (message->header_padding == copy->header_padding); -   -  _dbus_assert (_dbus_string_get_length (&message->header) == -                _dbus_string_get_length (©->header)); + +  _dbus_assert (dbus_message_get_reply_serial (message) == +                dbus_message_get_reply_serial (copy)); +  _dbus_assert (message->header.padding == copy->header.padding); + +  _dbus_assert (_dbus_string_get_length (&message->header.data) == +                _dbus_string_get_length (©->header.data));    _dbus_assert (_dbus_string_get_length (&message->body) ==                  _dbus_string_get_length (©->body)); -   +    verify_test_message (copy);    name1 = dbus_message_get_interface (message); @@ -7464,10 +4582,12 @@ _dbus_message_test (const char *test_data_dir)    name2 = dbus_message_get_member (copy);    _dbus_assert (strcmp (name1, name2) == 0); -   -  dbus_message_unref (message);   + +  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", @@ -7510,14 +4630,14 @@ _dbus_message_test (const char *test_data_dir)    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); @@ -7529,7 +4649,7 @@ _dbus_message_test (const char *test_data_dir)    dbus_message_iter_append_byte (&iter, 0xF0);    message_iter_test (message); -   +    /* Message loader test */    _dbus_message_lock (message);    loader = _dbus_message_loader_new (); @@ -7537,7 +4657,7 @@ _dbus_message_test (const char *test_data_dir)    /* 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++) @@ -7566,19 +4686,19 @@ _dbus_message_test (const char *test_data_dir)    /* 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); @@ -7598,13 +4718,13 @@ _dbus_message_test (const char *test_data_dir)    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 @@ -7613,14 +4733,14 @@ _dbus_message_test (const char *test_data_dir)    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", @@ -7630,7 +4750,7 @@ _dbus_message_test (const char *test_data_dir)    _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"); @@ -7647,7 +4767,7 @@ _dbus_message_test (const char *test_data_dir)                    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"); @@ -7655,7 +4775,7 @@ _dbus_message_test (const char *test_data_dir)    _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     */ @@ -7669,15 +4789,15 @@ _dbus_message_test (const char *test_data_dir)    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_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; @@ -7686,6 +4806,10 @@ _dbus_message_test (const char *test_data_dir)                                                          (DBusForeachMessageFileFunc)                                                          dbus_internal_do_not_use_try_message_file,                                                          NULL); + +#endif /* Commented out most tests for now */ + +  return TRUE;  }  #endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index e1894c72..fd6b96d4 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -144,14 +144,6 @@ dbus_bool_t dbus_message_get_args_valist      (DBusMessage     *message,  					       DBusError       *error,  					       int              first_arg_type,  					       va_list          var_args); -dbus_bool_t dbus_message_iter_get_args        (DBusMessageIter *iter, -					       DBusError       *error, -					       int              first_arg_type, -					       ...); -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_init            (DBusMessage      *message, @@ -160,125 +152,29 @@ dbus_bool_t            dbus_message_iter_has_next        (DBusMessageIter  *iter  dbus_bool_t            dbus_message_iter_next            (DBusMessageIter  *iter);  int                    dbus_message_iter_get_arg_type    (DBusMessageIter  *iter);  int                    dbus_message_iter_get_array_type  (DBusMessageIter  *iter); -unsigned char          dbus_message_iter_get_byte        (DBusMessageIter  *iter); -dbus_bool_t            dbus_message_iter_get_boolean     (DBusMessageIter  *iter); -dbus_int32_t           dbus_message_iter_get_int32       (DBusMessageIter  *iter); -dbus_uint32_t          dbus_message_iter_get_uint32      (DBusMessageIter  *iter); -#ifdef DBUS_HAVE_INT64 -dbus_int64_t           dbus_message_iter_get_int64       (DBusMessageIter  *iter); -dbus_uint64_t          dbus_message_iter_get_uint64      (DBusMessageIter  *iter); -#endif /* DBUS_HAVE_INT64 */ -double                 dbus_message_iter_get_double      (DBusMessageIter  *iter); -char *                 dbus_message_iter_get_string      (DBusMessageIter  *iter); -char *                 dbus_message_iter_get_object_path (DBusMessageIter  *iter); -char *                 dbus_message_iter_get_dict_key    (DBusMessageIter  *iter); -dbus_bool_t            dbus_message_iter_get_custom      (DBusMessageIter  *iter, -                                                          char            **name, -                                                          unsigned char   **value, -                                                          int              *len); - -dbus_bool_t dbus_message_iter_init_array_iterator (DBusMessageIter   *iter, -						   DBusMessageIter   *array_iter, -						   int               *array_type); -dbus_bool_t dbus_message_iter_init_dict_iterator  (DBusMessageIter   *iter, -						   DBusMessageIter   *dict_iter); -dbus_bool_t dbus_message_iter_get_byte_array      (DBusMessageIter   *iter, -						   unsigned char    **value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_boolean_array   (DBusMessageIter   *iter, -						   unsigned char    **value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_int32_array     (DBusMessageIter   *iter, -						   dbus_int32_t     **value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_uint32_array    (DBusMessageIter   *iter, -						   dbus_uint32_t    **value, -						   int               *len); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t dbus_message_iter_get_int64_array     (DBusMessageIter   *iter, -						   dbus_int64_t     **value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_uint64_array    (DBusMessageIter   *iter, -						   dbus_uint64_t    **value, -						   int               *len); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t dbus_message_iter_get_double_array    (DBusMessageIter   *iter, -						   double           **value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_string_array    (DBusMessageIter   *iter, -						   char            ***value, -						   int               *len); -dbus_bool_t dbus_message_iter_get_object_path_array (DBusMessageIter   *iter, -                                                     char            ***value, -                                                     int               *len); - - -void        dbus_message_append_iter_init          (DBusMessage          *message, -						    DBusMessageIter      *iter); -dbus_bool_t dbus_message_iter_append_nil           (DBusMessageIter      *iter); -dbus_bool_t dbus_message_iter_append_boolean       (DBusMessageIter      *iter, -						    dbus_bool_t           value); -dbus_bool_t dbus_message_iter_append_byte          (DBusMessageIter      *iter, -						    unsigned char         value); -dbus_bool_t dbus_message_iter_append_int32         (DBusMessageIter      *iter, -						    dbus_int32_t          value); -dbus_bool_t dbus_message_iter_append_uint32        (DBusMessageIter      *iter, -						    dbus_uint32_t         value); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t dbus_message_iter_append_int64         (DBusMessageIter      *iter, -						    dbus_int64_t          value); -dbus_bool_t dbus_message_iter_append_uint64        (DBusMessageIter      *iter, -						    dbus_uint64_t         value); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t dbus_message_iter_append_double        (DBusMessageIter      *iter, -						    double                value); -dbus_bool_t dbus_message_iter_append_string        (DBusMessageIter      *iter, -						    const char           *value); -dbus_bool_t dbus_message_iter_append_object_path   (DBusMessageIter      *iter, -						    const char           *value); -dbus_bool_t dbus_message_iter_append_custom        (DBusMessageIter      *iter, -						    const char           *name, -						    const unsigned char  *data, -						    int                   len); -dbus_bool_t dbus_message_iter_append_dict_key      (DBusMessageIter      *iter, -						    const char           *value); -dbus_bool_t dbus_message_iter_append_array         (DBusMessageIter      *iter, -						    DBusMessageIter      *array_iter, -						    int                   element_type); -dbus_bool_t dbus_message_iter_append_dict          (DBusMessageIter      *iter, -						    DBusMessageIter      *dict_iter); - -/* Helpers for normal types: */ -dbus_bool_t dbus_message_iter_append_boolean_array (DBusMessageIter      *iter, -						    unsigned const char  *value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_int32_array   (DBusMessageIter      *iter, -						    const dbus_int32_t   *value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_uint32_array  (DBusMessageIter      *iter, -						    const dbus_uint32_t  *value, -						    int                   len); -#ifdef DBUS_HAVE_INT64 -dbus_bool_t dbus_message_iter_append_int64_array   (DBusMessageIter      *iter, -						    const dbus_int64_t   *value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_uint64_array  (DBusMessageIter      *iter, -						    const dbus_uint64_t  *value, -						    int                   len); -#endif /* DBUS_HAVE_INT64 */ -dbus_bool_t dbus_message_iter_append_double_array  (DBusMessageIter      *iter, -						    const double         *value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_byte_array    (DBusMessageIter      *iter, -						    unsigned const char  *value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_string_array  (DBusMessageIter      *iter, -						    const char          **value, -						    int                   len); -dbus_bool_t dbus_message_iter_append_object_path_array (DBusMessageIter      *iter, -							const char          **value, -							int                   len); - +void                   dbus_message_iter_recurse         (DBusMessageIter  *iter, +                                                          DBusMessageIter  *sub); +void                   dbus_message_iter_get_basic       (DBusMessageIter  *iter, +                                                          void             *value); +void                   dbus_message_iter_get_fixed_array (DBusMessageIter  *iter, +                                                          void             *value, +                                                          int              *n_elements); + +void        dbus_message_append_iter_init        (DBusMessage     *message, +                                                  DBusMessageIter *iter); +dbus_bool_t dbus_message_iter_append_basic       (DBusMessageIter *iter, +                                                  int              type, +                                                  const void      *value); +dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter *iter, +                                                  int              element_type, +                                                  const void      *value, +                                                  int              n_elements); +dbus_bool_t dbus_message_iter_open_container     (DBusMessageIter *iter, +                                                  int              type, +                                                  const char      *contained_signature, +                                                  DBusMessageIter *sub); +dbus_bool_t dbus_message_iter_close_container    (DBusMessageIter *iter, +                                                  DBusMessageIter *sub);  dbus_bool_t  dbus_set_error_from_message  (DBusError    *error, diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index afce2442..694185fb 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -937,7 +937,96 @@ _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,    return result;  } -      + + +/** Set to 1 to get a bunch of spew about disassembling the path string */ +#define VERBOSE_DECOMPOSE 0 + +/** + * Decompose an object path.  A path of just "/" is + * represented as an empty vector of strings. + *  + * @param data the path data + * @param len  the length of the path string + * @param path address to store new object path + * @param path_len length of stored path + */ +dbus_bool_t +_dbus_decompose_path (const char*     data, +                      int             len, +                      char         ***path, +                      int            *path_len) +{ +  char **retval; +  int n_components; +  int i, j, comp; + +  _dbus_assert (data != NULL); + +#if VERBOSE_DECOMPOSE +  _dbus_verbose ("Decomposing path \"%s\"\n", +                 data); +#endif +   +  n_components = 0; +  i = 0; +  while (i < len) +    { +      if (data[i] == '/') +        n_components += 1; +      ++i; +    } +   +  retval = dbus_new0 (char*, n_components + 1); + +  if (retval == NULL) +    return FALSE; + +  comp = 0; +  i = 0; +  while (i < len) +    { +      if (data[i] == '/') +        ++i; +      j = i; + +      while (j < len && data[j] != '/') +        ++j; + +      /* Now [i, j) is the path component */ +      _dbus_assert (i < j); +      _dbus_assert (data[i] != '/'); +      _dbus_assert (j == len || data[j] == '/'); + +#if VERBOSE_DECOMPOSE +      _dbus_verbose ("  (component in [%d,%d))\n", +                     i, j); +#endif +       +      retval[comp] = _dbus_memdup (&data[i], j - i + 1); +      if (retval[comp] == NULL) +        { +          dbus_free_string_array (retval); +          return FALSE; +        } +      retval[comp][j-i] = '\0'; +#if VERBOSE_DECOMPOSE +      _dbus_verbose ("  (component %d = \"%s\")\n", +                     comp, retval[comp]); +#endif + +      ++comp; +      i = j; +    } +  _dbus_assert (i == len); +   +  *path = retval; +  if (path_len) +    *path_len = n_components; +   +  return TRUE; +} +  /** @} */  #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h index 52d5bca1..6d8484e0 100644 --- a/dbus/dbus-object-tree.h +++ b/dbus/dbus-object-tree.h @@ -47,6 +47,12 @@ void              _dbus_object_tree_free_all_unlocked     (DBusObjectTree  dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,                                                            const char    **parent_path,                                                            char         ***child_entries); + +dbus_bool_t _dbus_decompose_path (const char   *data, +                                  int           len, +                                  char       ***path, +                                  int          *path_len); +  DBUS_END_DECLS  #endif /* DBUS_OBJECT_TREE_H */ diff --git a/dbus/dbus-protocol-new.h b/dbus/dbus-protocol-new.h deleted file mode 100644 index 482500f2..00000000 --- a/dbus/dbus-protocol-new.h +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-protocol.h  D-Bus protocol constants - * - * Copyright (C) 2002, 2003  CodeFactory AB - * Copyright (C) 2004 Red Hat, Inc. - * - * Licensed under the Academic Free License version 2.1 - *  - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - *  - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA - * - */ - -#ifndef DBUS_PROTOCOL_H -#define DBUS_PROTOCOL_H - -/* Don't include anything in here from anywhere else. It's - * intended for use by any random library. - */ - -#ifdef  __cplusplus -extern "C" { -#endif - -/* Message byte order */ -#define DBUS_LITTLE_ENDIAN ('l')  /* LSB first */ -#define DBUS_BIG_ENDIAN    ('B')  /* MSB first */     - -/* Protocol version */ -#define DBUS_MAJOR_PROTOCOL_VERSION 1 - -/* Never a legitimate type */ -#define DBUS_TYPE_INVALID       ((int) '\0') -#define DBUS_TYPE_INVALID_AS_STRING        "\0" - -/* Primitive types */ -#define DBUS_TYPE_BYTE          ((int) 'y') -#define DBUS_TYPE_BYTE_AS_STRING           "y" -#define DBUS_TYPE_BOOLEAN       ((int) 'b') -#define DBUS_TYPE_BOOLEAN_AS_STRING        "b" -#define DBUS_TYPE_INT32         ((int) 'i') -#define DBUS_TYPE_INT32_AS_STRING          "i" - -#define DBUS_TYPE_UINT32        ((int) 'u') -#define DBUS_TYPE_UINT32_AS_STRING         "u" -#define DBUS_TYPE_INT64         ((int) 'x') -#define DBUS_TYPE_INT64_AS_STRING          "x" -#define DBUS_TYPE_UINT64        ((int) 't') -#define DBUS_TYPE_UINT64_AS_STRING         "t" - -#define DBUS_TYPE_DOUBLE        ((int) 'd') -#define DBUS_TYPE_DOUBLE_AS_STRING         "d" -#define DBUS_TYPE_STRING        ((int) 's') -#define DBUS_TYPE_STRING_AS_STRING         "s" -#define DBUS_TYPE_OBJECT_PATH   ((int) 'o') -#define DBUS_TYPE_OBJECT_PATH_AS_STRING    "o" -#define DBUS_TYPE_SIGNATURE     ((int) 'g') -#define DBUS_TYPE_SIGNATURE_AS_STRING      "g" - -/* Compound types */ -#define DBUS_TYPE_ARRAY         ((int) 'a') -#define DBUS_TYPE_ARRAY_AS_STRING          "a" -#define DBUS_TYPE_VARIANT       ((int) 'v') -#define DBUS_TYPE_VARIANT_AS_STRING        "v" - -/* STRUCT is sort of special since its code can't appear in a type string, - * instead DBUS_STRUCT_BEGIN_CHAR has to appear - */ -#define DBUS_TYPE_STRUCT        ((int) 'r') -#define DBUS_TYPE_STRUCT_AS_STRING         "r" - -/* Does not count INVALID */ -#define DBUS_NUMBER_OF_TYPES    (13) - -/* characters other than typecodes that appear in type signatures */ -#define DBUS_STRUCT_BEGIN_CHAR   ((int) '(') -#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING   "(" -#define DBUS_STRUCT_END_CHAR     ((int) ')') -#define DBUS_STRUCT_END_CHAR_AS_STRING     ")" - -/* Max length in bytes of a service or interface or member name (not - * object path, paths are unlimited). This is limited because lots of - * stuff is O(n) in this number, plus it would be obnoxious to type in - * a paragraph-long method name so most likely something like that - * would be an exploit. - */ -#define DBUS_MAXIMUM_NAME_LENGTH 255 - -/* This one is 255 so it fits in a byte */ -#define DBUS_MAXIMUM_SIGNATURE_LENGTH 255 - -/* Max length of a match rule string; to keep people from hosing the - * daemon with some huge rule - */ -#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 - -/* Max length of a marshaled array in bytes (64M, 2^26) We use signed - * int for lengths so must be INT_MAX or less.  We need something a - * bit smaller than INT_MAX because the array is inside a message with - * header info, etc.  so an INT_MAX array wouldn't allow the message - * overhead.  The 64M number is an attempt at a larger number than - * we'd reasonably ever use, but small enough that your bus would chew - * through it fairly quickly without locking up forever. If you have - * data that's likely to be larger than this, you should probably be - * sending it in multiple incremental messages anyhow. - */ -#define DBUS_MAXIMUM_ARRAY_LENGTH (67108864) -/* Number of bits you need in an unsigned to store the max array size */ -#define DBUS_MAXIMUM_ARRAY_LENGTH_BITS 26 - -/* The maximum total message size including header and body; similar - * rationale to max array size. - */ -#define DBUS_MAXIMUM_MESSAGE_LENGTH (DBUS_MAXIMUM_ARRAY_LENGTH * 2) -/* Number of bits you need in an unsigned to store the max message size */ -#define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27 - -/* Types of message */ -#define DBUS_MESSAGE_TYPE_INVALID       0 -#define DBUS_MESSAGE_TYPE_METHOD_CALL   1 -#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 -#define DBUS_MESSAGE_TYPE_ERROR         3 -#define DBUS_MESSAGE_TYPE_SIGNAL        4 -   -/* Header flags */ -#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 -#define DBUS_HEADER_FLAG_AUTO_ACTIVATION   0x2 -   -/* Header fields */ -#define DBUS_HEADER_FIELD_INVALID        0 -#define DBUS_HEADER_FIELD_PATH           1 -#define DBUS_HEADER_FIELD_INTERFACE      2 -#define DBUS_HEADER_FIELD_MEMBER         3 -#define DBUS_HEADER_FIELD_ERROR_NAME     4 -#define DBUS_HEADER_FIELD_REPLY_SERIAL   5 -#define DBUS_HEADER_FIELD_DESTINATION    6 -#define DBUS_HEADER_FIELD_SENDER         7 -#define DBUS_HEADER_FIELD_SIGNATURE      8 - -#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SIGNATURE - -/* Services */ -#define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS      "org.freedesktop.DBus" - -/* Paths */ -#define DBUS_PATH_ORG_FREEDESKTOP_DBUS  "/org/freedesktop/DBus" -#define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local" -   -/* Interfaces, these #define don't do much other than - * catch typos at compile time - */ -#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS  "org.freedesktop.DBus" -#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable" -   -/* This is a special interface whose methods can only be invoked - * by the local implementation (messages from remote apps aren't - * allowed to specify this interface). - */ -#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local" -   -/* Service owner flags */ -#define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1 -#define DBUS_SERVICE_FLAG_REPLACE_EXISTING     0x2 - -/* Service replies */ -#define DBUS_SERVICE_REPLY_PRIMARY_OWNER  0x1 -#define DBUS_SERVICE_REPLY_IN_QUEUE       0x2 -#define DBUS_SERVICE_REPLY_SERVICE_EXISTS 0x4 -#define DBUS_SERVICE_REPLY_ALREADY_OWNER  0x8 - -/* Activation replies */ -#define DBUS_ACTIVATION_REPLY_ACTIVATED      0x0 -#define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1 - -/* Errors */ -/* WARNING these get autoconverted to an enum in dbus-glib.h. Thus, - * if you change the order it breaks the ABI. Keep them in order. - * Also, don't change the formatting since that will break the sed - * script. - */ -#define DBUS_ERROR_FAILED                     "org.freedesktop.DBus.Error.Failed" -#define DBUS_ERROR_NO_MEMORY                  "org.freedesktop.DBus.Error.NoMemory" -#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.ServiceNotFound" -#define DBUS_ERROR_SERVICE_DOES_NOT_EXIST     "org.freedesktop.DBus.Error.ServiceDoesNotExist" -#define DBUS_ERROR_SERVICE_HAS_NO_OWNER       "org.freedesktop.DBus.Error.ServiceHasNoOwner" -#define DBUS_ERROR_NO_REPLY                   "org.freedesktop.DBus.Error.NoReply" -#define DBUS_ERROR_IO_ERROR                   "org.freedesktop.DBus.Error.IOError" -#define DBUS_ERROR_BAD_ADDRESS                "org.freedesktop.DBus.Error.BadAddress" -#define DBUS_ERROR_NOT_SUPPORTED              "org.freedesktop.DBus.Error.NotSupported" -#define DBUS_ERROR_LIMITS_EXCEEDED            "org.freedesktop.DBus.Error.LimitsExceeded" -#define DBUS_ERROR_ACCESS_DENIED              "org.freedesktop.DBus.Error.AccessDenied" -#define DBUS_ERROR_AUTH_FAILED                "org.freedesktop.DBus.Error.AuthFailed" -#define DBUS_ERROR_NO_SERVER                  "org.freedesktop.DBus.Error.NoServer" -#define DBUS_ERROR_TIMEOUT                    "org.freedesktop.DBus.Error.Timeout" -#define DBUS_ERROR_NO_NETWORK                 "org.freedesktop.DBus.Error.NoNetwork" -#define DBUS_ERROR_ADDRESS_IN_USE             "org.freedesktop.DBus.Error.AddressInUse" -#define DBUS_ERROR_DISCONNECTED               "org.freedesktop.DBus.Error.Disconnected" -#define DBUS_ERROR_INVALID_ARGS               "org.freedesktop.DBus.Error.InvalidArgs" -#define DBUS_ERROR_FILE_NOT_FOUND             "org.freedesktop.DBus.Error.FileNotFound" -#define DBUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod" -#define DBUS_ERROR_TIMED_OUT                  "org.freedesktop.DBus.Error.TimedOut" -#define DBUS_ERROR_MATCH_RULE_NOT_FOUND       "org.freedesktop.DBus.Error.MatchRuleNotFound" -#define DBUS_ERROR_MATCH_RULE_INVALID         "org.freedesktop.DBus.Error.MatchRuleInvalid" -#define DBUS_ERROR_SPAWN_EXEC_FAILED          "org.freedesktop.DBus.Error.Spawn.ExecFailed" -#define DBUS_ERROR_SPAWN_FORK_FAILED          "org.freedesktop.DBus.Error.Spawn.ForkFailed" -#define DBUS_ERROR_SPAWN_CHILD_EXITED         "org.freedesktop.DBus.Error.Spawn.ChildExited" -#define DBUS_ERROR_SPAWN_CHILD_SIGNALED       "org.freedesktop.DBus.Error.Spawn.ChildSignaled" -#define DBUS_ERROR_SPAWN_FAILED               "org.freedesktop.DBus.Error.Spawn.Failed" -#define DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN    "org.freedesktop.DBus.Error.UnixProcessIdUnknown" - -#ifdef __cplusplus -} -#endif - -#endif /* DBUS_PROTOCOL_H */ diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index ce49a38d..6edd84f1 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -2,9 +2,10 @@  /* dbus-protocol.h  D-Bus protocol constants   *   * Copyright (C) 2002, 2003  CodeFactory AB + * 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 @@ -14,7 +15,7 @@   * 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 @@ -34,46 +35,115 @@ extern "C" {  /* Message byte order */  #define DBUS_LITTLE_ENDIAN ('l')  /* LSB first */ -#define DBUS_BIG_ENDIAN    ('B')  /* MSB first */     +#define DBUS_BIG_ENDIAN    ('B')  /* MSB first */  /* Protocol version */ -#define DBUS_MAJOR_PROTOCOL_VERSION 0 +#define DBUS_MAJOR_PROTOCOL_VERSION 1 -/* Data types */ +/* Never a legitimate type */  #define DBUS_TYPE_INVALID       ((int) '\0') -#define DBUS_TYPE_NIL           ((int) 'v') +#define DBUS_TYPE_INVALID_AS_STRING        "\0" + +/* Primitive types */  #define DBUS_TYPE_BYTE          ((int) 'y') +#define DBUS_TYPE_BYTE_AS_STRING           "y"  #define DBUS_TYPE_BOOLEAN       ((int) 'b') +#define DBUS_TYPE_BOOLEAN_AS_STRING        "b"  #define DBUS_TYPE_INT32         ((int) 'i') +#define DBUS_TYPE_INT32_AS_STRING          "i" +  #define DBUS_TYPE_UINT32        ((int) 'u') +#define DBUS_TYPE_UINT32_AS_STRING         "u"  #define DBUS_TYPE_INT64         ((int) 'x') +#define DBUS_TYPE_INT64_AS_STRING          "x"  #define DBUS_TYPE_UINT64        ((int) 't') +#define DBUS_TYPE_UINT64_AS_STRING         "t" +  #define DBUS_TYPE_DOUBLE        ((int) 'd') +#define DBUS_TYPE_DOUBLE_AS_STRING         "d"  #define DBUS_TYPE_STRING        ((int) 's') -#define DBUS_TYPE_CUSTOM        ((int) 'c') -#define DBUS_TYPE_ARRAY         ((int) 'a') -#define DBUS_TYPE_DICT          ((int) 'm') +#define DBUS_TYPE_STRING_AS_STRING         "s"  #define DBUS_TYPE_OBJECT_PATH   ((int) 'o') +#define DBUS_TYPE_OBJECT_PATH_AS_STRING    "o" +#define DBUS_TYPE_SIGNATURE     ((int) 'g') +#define DBUS_TYPE_SIGNATURE_AS_STRING      "g" + +/* Compound types */ +#define DBUS_TYPE_ARRAY         ((int) 'a') +#define DBUS_TYPE_ARRAY_AS_STRING          "a" +#define DBUS_TYPE_VARIANT       ((int) 'v') +#define DBUS_TYPE_VARIANT_AS_STRING        "v" +/* STRUCT is sort of special since its code can't appear in a type string, + * instead DBUS_STRUCT_BEGIN_CHAR has to appear + */ +#define DBUS_TYPE_STRUCT        ((int) 'r') +#define DBUS_TYPE_STRUCT_AS_STRING         "r" + +/* Does not count INVALID */  #define DBUS_NUMBER_OF_TYPES    (13) -/* Max length in bytes of a service or interface or member name */ -#define DBUS_MAXIMUM_NAME_LENGTH 256 +/* characters other than typecodes that appear in type signatures */ +#define DBUS_STRUCT_BEGIN_CHAR   ((int) '(') +#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING   "(" +#define DBUS_STRUCT_END_CHAR     ((int) ')') +#define DBUS_STRUCT_END_CHAR_AS_STRING     ")" + +/* Max length in bytes of a service or interface or member name (not + * object path, paths are unlimited). This is limited because lots of + * stuff is O(n) in this number, plus it would be obnoxious to type in + * a paragraph-long method name so most likely something like that + * would be an exploit. + */ +#define DBUS_MAXIMUM_NAME_LENGTH 255 -/* Max length of a match rule string */ +/* This one is 255 so it fits in a byte */ +#define DBUS_MAXIMUM_SIGNATURE_LENGTH 255 + +/* Max length of a match rule string; to keep people from hosing the + * daemon with some huge rule + */  #define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 +/* Max length of a marshaled array in bytes (64M, 2^26) We use signed + * int for lengths so must be INT_MAX or less.  We need something a + * bit smaller than INT_MAX because the array is inside a message with + * header info, etc.  so an INT_MAX array wouldn't allow the message + * overhead.  The 64M number is an attempt at a larger number than + * we'd reasonably ever use, but small enough that your bus would chew + * through it fairly quickly without locking up forever. If you have + * data that's likely to be larger than this, you should probably be + * sending it in multiple incremental messages anyhow. + */ +#define DBUS_MAXIMUM_ARRAY_LENGTH (67108864) +/* Number of bits you need in an unsigned to store the max array size */ +#define DBUS_MAXIMUM_ARRAY_LENGTH_BITS 26 + +/* The maximum total message size including header and body; similar + * rationale to max array size. + */ +#define DBUS_MAXIMUM_MESSAGE_LENGTH (DBUS_MAXIMUM_ARRAY_LENGTH * 2) +/* Number of bits you need in an unsigned to store the max message size */ +#define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27 + +/* Depth of recursion in the type tree. This is automatically limited + * to DBUS_MAXIMUM_SIGNATURE_LENGTH since you could only have an array + * of array of array of ... that fit in the max signature.  But that's + * probably a bit too large. + */ +#define DBUS_MAXIMUM_TYPE_RECURSION_DEPTH 32 +  /* Types of message */  #define DBUS_MESSAGE_TYPE_INVALID       0  #define DBUS_MESSAGE_TYPE_METHOD_CALL   1  #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2  #define DBUS_MESSAGE_TYPE_ERROR         3  #define DBUS_MESSAGE_TYPE_SIGNAL        4 -   +  /* Header flags */  #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1  #define DBUS_HEADER_FLAG_AUTO_ACTIVATION   0x2 -   +  /* Header fields */  #define DBUS_HEADER_FIELD_INVALID        0  #define DBUS_HEADER_FIELD_PATH           1 @@ -87,25 +157,52 @@ extern "C" {  #define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SIGNATURE +/* Header format is defined as a signature: + *   byte                            byte order + *   byte                            message type ID + *   byte                            flags + *   byte                            protocol version + *   uint32                          body length + *   uint32                          serial + *   array of struct (byte,variant)  (field name, value) + * + * The length of the header can be computed as the + * fixed size of the initial data, plus the length of + * the array at the end, plus padding to an 8-boundary. + */ +#define DBUS_HEADER_SIGNATURE                   \ +     DBUS_TYPE_BYTE_AS_STRING                   \ +     DBUS_TYPE_BYTE_AS_STRING                   \ +     DBUS_TYPE_BYTE_AS_STRING                   \ +     DBUS_TYPE_BYTE_AS_STRING                   \ +     DBUS_TYPE_UINT32_AS_STRING                 \ +     DBUS_TYPE_UINT32_AS_STRING                 \ +     DBUS_TYPE_ARRAY_AS_STRING                  \ +     DBUS_STRUCT_BEGIN_CHAR_AS_STRING           \ +     DBUS_TYPE_BYTE_AS_STRING                   \ +     DBUS_TYPE_VARIANT_AS_STRING                \ +     DBUS_STRUCT_END_CHAR_AS_STRING + +  /* Services */  #define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS      "org.freedesktop.DBus"  /* Paths */  #define DBUS_PATH_ORG_FREEDESKTOP_DBUS  "/org/freedesktop/DBus"  #define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local" -   +  /* Interfaces, these #define don't do much other than   * catch typos at compile time   */  #define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS  "org.freedesktop.DBus"  #define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable" -   +  /* This is a special interface whose methods can only be invoked   * by the local implementation (messages from remote apps aren't   * allowed to specify this interface).   */  #define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local" -   +  /* Service owner flags */  #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1  #define DBUS_SERVICE_FLAG_REPLACE_EXISTING     0x2 diff --git a/dbus/dbus-sha.c b/dbus/dbus-sha.c index d26fb320..b386e452 100644 --- a/dbus/dbus-sha.c +++ b/dbus/dbus-sha.c @@ -23,8 +23,8 @@   */  #include "dbus-internals.h" -#include "dbus-marshal.h"  #include "dbus-sha.h" +#include "dbus-marshal-basic.h" /* for byteswap routines */  #include <string.h>  /* The following comments have the history of where this code diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 7040e155..777461ed 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -27,10 +27,11 @@  #include <string.h>  /* for vsnprintf */  #include <stdio.h> -#include "dbus-marshal.h"  #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1  #include "dbus-string-private.h" -#include "dbus-protocol.h" +#include "dbus-marshal-basic.h" /* probably should be removed by moving the usage of DBUS_TYPE +                                 * into the marshaling-related files +                                 */  /* for DBUS_VA_COPY */  #include "dbus-sysdeps.h" @@ -78,24 +79,17 @@   */  /** - * We allocate 1 byte for nul termination, plus 7 bytes for possible - * align_offset, so we always need 8 bytes on top of the string's - * length to be in the allocated block. - */ -#define ALLOCATION_PADDING 8 - -/**   * This is the maximum max length (and thus also the maximum length)   * of a DBusString   */ -#define MAX_MAX_LENGTH (_DBUS_INT_MAX - ALLOCATION_PADDING) +#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 - ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length) +#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 @@ -142,7 +136,7 @@ fixup_alignment (DBusRealString *real)    unsigned int old_align_offset;    /* we have to have extra space in real->allocated for the align offset and nul byte */ -  _dbus_assert (real->len <= real->allocated - ALLOCATION_PADDING); +  _dbus_assert (real->len <= real->allocated - _DBUS_STRING_ALLOCATION_PADDING);    old_align_offset = real->align_offset;    real_block = real->str - old_align_offset; @@ -205,11 +199,11 @@ _dbus_string_init_preallocated (DBusString *str,     * an existing string, e.g. in _dbus_string_steal_data()     */ -  real->str = dbus_malloc (ALLOCATION_PADDING + allocate_size); +  real->str = dbus_malloc (_DBUS_STRING_ALLOCATION_PADDING + allocate_size);    if (real->str == NULL)      return FALSE;   -  real->allocated = ALLOCATION_PADDING + allocate_size; +  real->allocated = _DBUS_STRING_ALLOCATION_PADDING + allocate_size;    real->len = 0;    real->str[real->len] = '\0'; @@ -299,10 +293,12 @@ _dbus_string_init_const_len (DBusString *str,    real->str = (char*) value;    real->len = len; -  real->allocated = real->len + ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */ +  real->allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */    real->max_length = real->len + 1;    real->constant = TRUE; +  real->locked = TRUE;    real->invalid = FALSE; +  real->align_offset = 0;    /* We don't require const strings to be 8-byte aligned as the     * memory is coming from elsewhere. @@ -356,7 +352,7 @@ _dbus_string_lock (DBusString *str)        char *new_str;        int new_allocated; -      new_allocated = real->len + ALLOCATION_PADDING; +      new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING;        new_str = dbus_realloc (real->str - real->align_offset,                                new_allocated); @@ -380,8 +376,8 @@ reallocate_for_length (DBusRealString *real,    /* at least double our old allocation to avoid O(n), avoiding     * overflow     */ -  if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2) -    new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING; +  if (real->allocated > (MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2) +    new_allocated = MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING;    else      new_allocated = real->allocated * 2; @@ -403,7 +399,7 @@ reallocate_for_length (DBusRealString *real,    /* But be sure we always alloc at least space for the new length */    new_allocated = MAX (new_allocated, -                       new_length + ALLOCATION_PADDING); +                       new_length + _DBUS_STRING_ALLOCATION_PADDING);    _dbus_assert (new_allocated >= real->allocated); /* code relies on this */    new_str = dbus_realloc (real->str - real->align_offset, new_allocated); @@ -426,7 +422,7 @@ set_length (DBusRealString *real,    /* exceeding max length is the same as failure to allocate memory */    if (_DBUS_UNLIKELY (new_length > real->max_length))      return FALSE; -  else if (new_length > (real->allocated - ALLOCATION_PADDING) && +  else if (new_length > (real->allocated - _DBUS_STRING_ALLOCATION_PADDING) &&             _DBUS_UNLIKELY (!reallocate_for_length (real, new_length)))      return FALSE;    else @@ -1179,10 +1175,10 @@ _dbus_string_insert_alignment (DBusString        *str,  {    DBUS_STRING_PREAMBLE (str); -  if (!align_insert_point_then_open_gap (str, insert_at, 8, 0)) +  if (!align_insert_point_then_open_gap (str, insert_at, alignment, 0))      return FALSE; -  _dbus_assert (_DBUS_ALIGN_VALUE (*insert_at, 8) == (unsigned) *insert_at); +  _dbus_assert (_DBUS_ALIGN_VALUE (*insert_at, alignment) == (unsigned) *insert_at);    return TRUE;  } @@ -2753,387 +2749,6 @@ _dbus_string_validate_nul (const DBusString *str,  }  /** - * Checks that the given range of the string is a valid object path - * name in the D-BUS protocol. This includes a length restriction, - * etc., see the specification. It does not validate UTF-8, that has - * to be done separately for now. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - * - * @todo change spec to disallow more things, such as spaces in the - * path name - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_string_validate_path (const DBusString  *str, -                            int                start, -                            int                len) -{ -  const unsigned char *s; -  const unsigned char *end; -  const unsigned char *last_slash; -   -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start >= 0); -  _dbus_assert (len >= 0); -  _dbus_assert (start <= real->len); -   -  if (len > real->len - start) -    return FALSE; - -  if (len > DBUS_MAXIMUM_NAME_LENGTH) -    return FALSE; - -  if (len == 0) -    return FALSE; - -  s = real->str + start; -  end = s + len; - -  if (*s != '/') -    return FALSE; -  last_slash = s; -  ++s; -   -  while (s != end) -    { -      if (*s == '/') -        { -          if ((s - last_slash) < 2) -            return FALSE; /* no empty path components allowed */ - -          last_slash = s; -        } -       -      ++s; -    } - -  if ((end - last_slash) < 2 && -      len > 1) -    return FALSE; /* trailing slash not allowed unless the string is "/" */ -   -  return TRUE; -} - -/** - * Determine wether the given charater is valid as the first charater - * in a name. - */ -#define VALID_INITIAL_NAME_CHARACTER(c)         \ -  ( ((c) >= 'A' && (c) <= 'Z') ||               \ -    ((c) >= 'a' && (c) <= 'z') ||               \ -    ((c) == '_') ) - -/** - * Determine wether the given charater is valid as a second or later - * character in a nam - */ -#define VALID_NAME_CHARACTER(c)                 \ -  ( ((c) >= '0' && (c) <= '9') ||               \ -    ((c) >= 'A' && (c) <= 'Z') ||               \ -    ((c) >= 'a' && (c) <= 'z') ||               \ -    ((c) == '_') ) - -/** - * Checks that the given range of the string is a valid interface name - * in the D-BUS protocol. This includes a length restriction and an - * ASCII subset, see the specification. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_string_validate_interface (const DBusString  *str, -                                 int                start, -                                 int                len) -{   -  const unsigned char *s; -  const unsigned char *end; -  const unsigned char *iface; -  const unsigned char *last_dot; -   -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start >= 0); -  _dbus_assert (len >= 0); -  _dbus_assert (start <= real->len); -   -  if (len > real->len - start) -    return FALSE; - -  if (len > DBUS_MAXIMUM_NAME_LENGTH) -    return FALSE; - -  if (len == 0) -    return FALSE; - -  last_dot = NULL; -  iface = real->str + start; -  end = iface + len; -  s = iface; - -  /* check special cases of first char so it doesn't have to be done -   * in the loop. Note we know len > 0 -   */ -  if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ -    return FALSE; -  else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) -    return FALSE; -  else -    ++s; -   -  while (s != end) -    { -      if (*s == '.') -        { -          if (_DBUS_UNLIKELY ((s + 1) == end)) -            return FALSE; -          else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1)))) -            return FALSE; -          last_dot = s; -          ++s; /* we just validated the next char, so skip two */ -        } -      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) -        { -          return FALSE; -        } -       -      ++s; -    } - -  if (_DBUS_UNLIKELY (last_dot == NULL)) -    return FALSE; -   -  return TRUE; -} - -/** - * Checks that the given range of the string is a valid member name - * in the D-BUS protocol. This includes a length restriction, etc., - * see the specification. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_string_validate_member (const DBusString  *str, -                              int                start, -                              int                len) -{ -  const unsigned char *s; -  const unsigned char *end; -  const unsigned char *member; -   -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start >= 0); -  _dbus_assert (len >= 0); -  _dbus_assert (start <= real->len); -   -  if (len > real->len - start) -    return FALSE; - -  if (len > DBUS_MAXIMUM_NAME_LENGTH) -    return FALSE; - -  if (len == 0) -    return FALSE; - -  member = real->str + start; -  end = member + len; -  s = member; - -  /* check special cases of first char so it doesn't have to be done -   * in the loop. Note we know len > 0 -   */ - -  if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) -    return FALSE; -  else -    ++s; -   -  while (s != end) -    { -      if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) -        { -          return FALSE; -        } -       -      ++s; -    } -   -  return TRUE; -} - -/** - * Checks that the given range of the string is a valid error name - * in the D-BUS protocol. This includes a length restriction, etc., - * see the specification. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_string_validate_error_name (const DBusString  *str, -                                  int                start, -                                  int                len) -{ -  /* Same restrictions as interface name at the moment */ -  return _dbus_string_validate_interface (str, start, len); -} - -/* This assumes the first char exists and is ':' */ -static dbus_bool_t -_dbus_string_validate_base_service (const DBusString  *str, -                                    int                start, -                                    int                len) -{ -  const unsigned char *s; -  const unsigned char *end; -  const unsigned char *service; -   -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start >= 0); -  _dbus_assert (len >= 0); -  _dbus_assert (start <= real->len); -   -  if (len > real->len - start) -    return FALSE; - -  if (len > DBUS_MAXIMUM_NAME_LENGTH) -    return FALSE; - -  _dbus_assert (len > 0); - -  service = real->str + start; -  end = service + len; -  _dbus_assert (*service == ':'); -  s = service + 1; -   -  while (s != end) -    { -      if (*s == '.') -        { -          if (_DBUS_UNLIKELY ((s + 1) == end)) -            return FALSE; -          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1)))) -            return FALSE; -          ++s; /* we just validated the next char, so skip two */ -        } -      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) -        { -          return FALSE; -        } -       -      ++s; -    } -   -  return TRUE; -} - -/** - * Checks that the given range of the string is a valid service name - * in the D-BUS protocol. This includes a length restriction, etc., - * see the specification. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid name - */ -dbus_bool_t -_dbus_string_validate_service (const DBusString  *str, -                               int                start, -                               int                len) -{ -  if (_DBUS_UNLIKELY (len == 0)) -    return FALSE; -  if (_dbus_string_get_byte (str, start) == ':') -    return _dbus_string_validate_base_service (str, start, len); -  else -    return _dbus_string_validate_interface (str, start, len); -} - -/** - * Checks that the given range of the string is a valid message type - * signature in the D-BUS protocol. - * - * @todo this is inconsistent with most of DBusString in that - * it allows a start,len range that extends past the string end. - *  - * @param str the string - * @param start first byte index to check - * @param len number of bytes to check - * @returns #TRUE if the byte range exists and is a valid signature - */ -dbus_bool_t -_dbus_string_validate_signature (const DBusString  *str, -                                 int                start, -                                 int                len) -{ -  const unsigned char *s; -  const unsigned char *end; -  DBUS_CONST_STRING_PREAMBLE (str); -  _dbus_assert (start >= 0); -  _dbus_assert (start <= real->len); -  _dbus_assert (len >= 0); -   -  if (len > real->len - start) -    return FALSE; -   -  s = real->str + start; -  end = s + len; -  while (s != end) -    { -      switch (*s) -        { -        case DBUS_TYPE_NIL: -        case DBUS_TYPE_BYTE: -        case DBUS_TYPE_BOOLEAN: -        case DBUS_TYPE_INT32: -        case DBUS_TYPE_UINT32: -        case DBUS_TYPE_INT64: -        case DBUS_TYPE_UINT64: -        case DBUS_TYPE_DOUBLE: -        case DBUS_TYPE_STRING: -        case DBUS_TYPE_CUSTOM: -        case DBUS_TYPE_ARRAY: -        case DBUS_TYPE_DICT: -        case DBUS_TYPE_OBJECT_PATH: -          break; -           -        default: -          return FALSE; -        } -       -      ++s; -    } -   -  return TRUE; -} - -/**   * Clears all allocated bytes in the string to zero.   *   * @param str the string @@ -3393,127 +3008,6 @@ _dbus_string_test (void)    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; -  const char *valid_paths[] = { -    "/", -    "/foo/bar", -    "/foo", -    "/foo/bar/baz" -  }; -  const char *invalid_paths[] = { -    "bar", -    "bar/baz", -    "/foo/bar/", -    "/foo/" -    "foo/", -    "boo//blah", -    "//", -    "///", -    "foo///blah/", -    "Hello World", -    "", -    "   ", -    "foo bar" -  }; - -  const char *valid_interfaces[] = { -    "org.freedesktop.Foo", -    "Bar.Baz", -    "Blah.Blah.Blah.Blah.Blah", -    "a.b", -    "a.b.c.d.e.f.g", -    "a0.b1.c2.d3.e4.f5.g6", -    "abc123.foo27" -  }; -  const char *invalid_interfaces[] = { -    ".", -    "", -    "..", -    ".Foo.Bar", -    "..Foo.Bar", -    "Foo.Bar.", -    "Foo.Bar..", -    "Foo", -    "9foo.bar.baz", -    "foo.bar..baz", -    "foo.bar...baz", -    "foo.bar.b..blah", -    ":", -    ":0-1", -    "10", -    ":11.34324", -    "0.0.0", -    "0..0", -    "foo.Bar.%", -    "foo.Bar!!", -    "!Foo.bar.bz", -    "foo.$.blah", -    "", -    "   ", -    "foo bar" -  }; - -  const char *valid_base_services[] = { -    ":0", -    ":a", -    ":", -    ":.a", -    ":.1", -    ":0.1", -    ":000.2222", -    ":.blah", -    ":abce.freedesktop.blah" -  }; -  const char *invalid_base_services[] = { -    ":-", -    ":!", -    ":0-10", -    ":blah.", -    ":blah.", -    ":blah..org", -    ":blah.org..", -    ":..blah.org", -    "", -    "   ", -    "foo bar" -  }; - -  const char *valid_members[] = { -    "Hello", -    "Bar", -    "foobar", -    "_foobar", -    "foo89" -  }; - -  const char *invalid_members[] = { -    "9Hello", -    "10", -    "1", -    "foo-bar", -    "blah.org", -    ".blah", -    "blah.", -    "Hello.", -    "!foo", -    "", -    "   ", -    "foo bar" -  }; - -  const char *valid_signatures[] = { -    "", -    "sss", -    "i", -    "b" -  }; - -  const char *invalid_signatures[] = { -    " ", -    "not a valid signature", -    "123", -    ".", -    "(" -  };    i = 0;    while (i < _DBUS_N_ELEMENTS (lens)) @@ -3901,284 +3395,6 @@ _dbus_string_test (void)    _dbus_string_free (&other);    test_roundtrips (test_hex_roundtrip); - -  /* Path validation */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_paths)) -    { -      _dbus_string_init_const (&str, valid_paths[i]); - -      if (!_dbus_string_validate_path (&str, 0, -                                       _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]); -          _dbus_assert_not_reached ("invalid path"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths)) -    { -      _dbus_string_init_const (&str, invalid_paths[i]); -       -      if (_dbus_string_validate_path (&str, 0, -                                      _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]); -          _dbus_assert_not_reached ("valid path"); -        } -       -      ++i; -    } - -  /* Interface validation */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) -    { -      _dbus_string_init_const (&str, valid_interfaces[i]); - -      if (!_dbus_string_validate_interface (&str, 0, -                                            _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]); -          _dbus_assert_not_reached ("invalid interface"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) -    { -      _dbus_string_init_const (&str, invalid_interfaces[i]); -       -      if (_dbus_string_validate_interface (&str, 0, -                                           _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]); -          _dbus_assert_not_reached ("valid interface"); -        } -       -      ++i; -    } - -  /* Service validation (check that valid interfaces are valid services, -   * and invalid interfaces are invalid services except if they start with ':') -   */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) -    { -      _dbus_string_init_const (&str, valid_interfaces[i]); - -      if (!_dbus_string_validate_service (&str, 0, -                                          _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Service \"%s\" should have been valid\n", valid_interfaces[i]); -          _dbus_assert_not_reached ("invalid service"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) -    { -      if (invalid_interfaces[i][0] != ':') -        { -          _dbus_string_init_const (&str, invalid_interfaces[i]); -           -          if (_dbus_string_validate_service (&str, 0, -                                             _dbus_string_get_length (&str))) -            { -              _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_interfaces[i]); -              _dbus_assert_not_reached ("valid service"); -            } -        } -       -      ++i; -    } - -  /* Base service validation */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_base_services)) -    { -      _dbus_string_init_const (&str, valid_base_services[i]); - -      if (!_dbus_string_validate_service (&str, 0, -                                          _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Service \"%s\" should have been valid\n", valid_base_services[i]); -          _dbus_assert_not_reached ("invalid base service"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_base_services)) -    { -      _dbus_string_init_const (&str, invalid_base_services[i]); -       -      if (_dbus_string_validate_service (&str, 0, -                                         _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_base_services[i]); -          _dbus_assert_not_reached ("valid base service"); -        } -       -      ++i; -    } - - -  /* Error name validation (currently identical to interfaces) -   */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) -    { -      _dbus_string_init_const (&str, valid_interfaces[i]); - -      if (!_dbus_string_validate_error_name (&str, 0, -                                             _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]); -          _dbus_assert_not_reached ("invalid error name"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) -    { -      if (invalid_interfaces[i][0] != ':') -        { -          _dbus_string_init_const (&str, invalid_interfaces[i]); -           -          if (_dbus_string_validate_error_name (&str, 0, -                                                _dbus_string_get_length (&str))) -            { -              _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]); -              _dbus_assert_not_reached ("valid error name"); -            } -        } -       -      ++i; -    } -   -  /* Member validation */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_members)) -    { -      _dbus_string_init_const (&str, valid_members[i]); - -      if (!_dbus_string_validate_member (&str, 0, -                                         _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]); -          _dbus_assert_not_reached ("invalid member"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_members)) -    { -      _dbus_string_init_const (&str, invalid_members[i]); -       -      if (_dbus_string_validate_member (&str, 0, -                                        _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]); -          _dbus_assert_not_reached ("valid member"); -        } -       -      ++i; -    } - -  /* Signature validation */ -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (valid_signatures)) -    { -      _dbus_string_init_const (&str, valid_signatures[i]); - -      if (!_dbus_string_validate_signature (&str, 0, -                                            _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]); -          _dbus_assert_not_reached ("invalid signature"); -        } -       -      ++i; -    } - -  i = 0; -  while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures)) -    { -      _dbus_string_init_const (&str, invalid_signatures[i]); -       -      if (_dbus_string_validate_signature (&str, 0, -                                           _dbus_string_get_length (&str))) -        { -          _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]); -          _dbus_assert_not_reached ("valid signature"); -        } -       -      ++i; -    } -   -  /* Validate claimed length longer than real length */ -  _dbus_string_init_const (&str, "abc.efg"); -  if (_dbus_string_validate_service (&str, 0, 8)) -    _dbus_assert_not_reached ("validated too-long string"); -  if (_dbus_string_validate_interface (&str, 0, 8)) -    _dbus_assert_not_reached ("validated too-long string"); -  if (_dbus_string_validate_error_name (&str, 0, 8)) -    _dbus_assert_not_reached ("validated too-long string"); - -  _dbus_string_init_const (&str, "abc"); -  if (_dbus_string_validate_member (&str, 0, 4)) -    _dbus_assert_not_reached ("validated too-long string"); - -  _dbus_string_init_const (&str, "sss"); -  if (_dbus_string_validate_signature (&str, 0, 4)) -    _dbus_assert_not_reached ("validated too-long signature"); -   -  /* Validate string exceeding max name length */ -  if (!_dbus_string_init (&str)) -    _dbus_assert_not_reached ("no memory"); - -  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) -    if (!_dbus_string_append (&str, "abc.def")) -      _dbus_assert_not_reached ("no memory"); - -  if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str))) -    _dbus_assert_not_reached ("validated overmax string"); -  if (_dbus_string_validate_interface (&str, 0, _dbus_string_get_length (&str))) -    _dbus_assert_not_reached ("validated overmax string"); -  if (_dbus_string_validate_error_name (&str, 0, _dbus_string_get_length (&str))) -    _dbus_assert_not_reached ("validated overmax string"); - -  /* overlong member */ -  _dbus_string_set_length (&str, 0); -  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) -    if (!_dbus_string_append (&str, "abc")) -      _dbus_assert_not_reached ("no memory");   - -  if (_dbus_string_validate_member (&str, 0, _dbus_string_get_length (&str))) -    _dbus_assert_not_reached ("validated overmax string"); - -  /* overlong base service */ -  _dbus_string_set_length (&str, 0); -  _dbus_string_append (&str, ":"); -  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) -    if (!_dbus_string_append (&str, "abc")) -      _dbus_assert_not_reached ("no memory");   - -  if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str))) -    _dbus_assert_not_reached ("validated overmax string");    _dbus_string_free (&str); diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 792b8194..f0ae1e65 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -39,10 +39,10 @@ DBUS_BEGIN_DECLS   */  struct DBusString  { -  void *dummy1; /**< placeholder */ -  int   dummy2; /**< placeholder */ -  int   dummy3; /**< placeholder */ -  int   dummy4; /**< placeholder */ +  const void *dummy1; /**< placeholder */ +  int   dummy2;       /**< placeholder */ +  int   dummy3;       /**< placeholder */ +  int   dummy4;       /**< placeholder */    unsigned int dummy5 : 1; /**< placeholder */    unsigned int dummy6 : 1; /**< placeholder */    unsigned int dummy7 : 1; /**< placeholder */ @@ -264,27 +264,32 @@ dbus_bool_t   _dbus_string_validate_utf8         (const DBusString  *str,  dbus_bool_t   _dbus_string_validate_nul          (const DBusString  *str,                                                    int                start,                                                    int                len); -dbus_bool_t   _dbus_string_validate_path         (const DBusString  *str, -                                                  int                start, -                                                  int                len); -dbus_bool_t   _dbus_string_validate_interface    (const DBusString  *str, -                                                  int                start, -                                                  int                len); -dbus_bool_t   _dbus_string_validate_member       (const DBusString  *str, -                                                  int                start, -                                                  int                len); -dbus_bool_t   _dbus_string_validate_error_name   (const DBusString  *str, -                                                  int                start, -                                                  int                len); -dbus_bool_t   _dbus_string_validate_service      (const DBusString  *str, -                                                  int                start, -                                                  int                len); -dbus_bool_t   _dbus_string_validate_signature    (const DBusString  *str, -                                                  int                start, -                                                  int                len);  void          _dbus_string_zero                  (DBusString        *str); +/** + * We allocate 1 byte for nul termination, plus 7 bytes for possible + * align_offset, so we always need 8 bytes on top of the string's + * length to be in the allocated block. + */ +#define _DBUS_STRING_ALLOCATION_PADDING 8 + +/** + * Defines a static const variable with type #DBusString called "name" + * containing the given string literal. + * + * @param name the name of the variable + * @param str the string value + */ +#define _DBUS_STRING_DEFINE_STATIC(name, str)                           \ +  static const char _dbus_static_string_##name[] = str;                 \ +  static const DBusString name = { _dbus_static_string_##name,          \ +                                   sizeof(_dbus_static_string_##name),  \ +                                   sizeof(_dbus_static_string_##name) + \ +                                   _DBUS_STRING_ALLOCATION_PADDING,     \ +                                   sizeof(_dbus_static_string_##name),  \ +                                   TRUE, TRUE, FALSE, 0 } +  DBUS_END_DECLS  #endif /* DBUS_STRING_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index df45ba6f..8654d86e 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -118,6 +118,16 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)    check_memleaks (); +#if 1 +  printf ("%s: running recursive marshalling tests\n", "dbus-test"); +  if (!_dbus_marshal_recursive_test ()) +    die ("recursive marshal"); + +  check_memleaks (); +#else +  _dbus_warn ("recursive marshal tests disabled\n"); +#endif +    printf ("%s: running memory tests\n", "dbus-test");    if (!_dbus_memory_test ())      die ("memory"); @@ -135,6 +145,18 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)      die ("lists");    check_memleaks (); + +  printf ("%s: running validation tests\n", "dbus-test"); +  if (!_dbus_marshal_validate_test ()) +    die ("validation"); + +  check_memleaks (); + +  printf ("%s: running header marshal tests\n", "dbus-test"); +  if (!_dbus_marshal_header_test ()) +    die ("header marshal"); + +  check_memleaks ();    printf ("%s: running message tests\n", "dbus-test");    if (!_dbus_message_test (test_data_dir)) @@ -197,5 +219,3 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)    printf ("Not compiled with unit tests, not running any\n");  #endif  } - - diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 1933c79b..b9865f09 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -35,26 +35,29 @@ typedef enum    _DBUS_MESSAGE_UNKNOWN  } DBusMessageValidity; -dbus_bool_t _dbus_hash_test            (void); -dbus_bool_t _dbus_dict_test            (void); -dbus_bool_t _dbus_list_test            (void); -dbus_bool_t _dbus_marshal_test         (void); -dbus_bool_t _dbus_mem_pool_test        (void); -dbus_bool_t _dbus_string_test          (void); -dbus_bool_t _dbus_address_test         (void); -dbus_bool_t _dbus_server_test          (void); -dbus_bool_t _dbus_message_test         (const char *test_data_dir); -dbus_bool_t _dbus_auth_test            (const char *test_data_dir); -dbus_bool_t _dbus_md5_test             (void); -dbus_bool_t _dbus_sha_test             (const char *test_data_dir); -dbus_bool_t _dbus_keyring_test         (void); -dbus_bool_t _dbus_data_slot_test       (void); -dbus_bool_t _dbus_sysdeps_test         (void); -dbus_bool_t _dbus_spawn_test           (const char *test_data_dir); -dbus_bool_t _dbus_userdb_test          (const char *test_data_dir); -dbus_bool_t _dbus_memory_test	       (void); -dbus_bool_t _dbus_object_tree_test     (void); -dbus_bool_t _dbus_pending_call_test    (const char *test_data_dir); +dbus_bool_t _dbus_hash_test              (void); +dbus_bool_t _dbus_dict_test              (void); +dbus_bool_t _dbus_list_test              (void); +dbus_bool_t _dbus_marshal_test           (void); +dbus_bool_t _dbus_marshal_recursive_test (void); +dbus_bool_t _dbus_marshal_header_test    (void); +dbus_bool_t _dbus_marshal_validate_test  (void); +dbus_bool_t _dbus_mem_pool_test          (void); +dbus_bool_t _dbus_string_test            (void); +dbus_bool_t _dbus_address_test           (void); +dbus_bool_t _dbus_server_test            (void); +dbus_bool_t _dbus_message_test           (const char *test_data_dir); +dbus_bool_t _dbus_auth_test              (const char *test_data_dir); +dbus_bool_t _dbus_md5_test               (void); +dbus_bool_t _dbus_sha_test               (const char *test_data_dir); +dbus_bool_t _dbus_keyring_test           (void); +dbus_bool_t _dbus_data_slot_test         (void); +dbus_bool_t _dbus_sysdeps_test           (void); +dbus_bool_t _dbus_spawn_test             (const char *test_data_dir); +dbus_bool_t _dbus_userdb_test            (const char *test_data_dir); +dbus_bool_t _dbus_memory_test            (void); +dbus_bool_t _dbus_object_tree_test       (void); +dbus_bool_t _dbus_pending_call_test      (const char *test_data_dir);  void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir);  dbus_bool_t dbus_internal_do_not_use_try_message_file  (const DBusString    *filename, @@ -15,11 +15,11 @@ Important for 1.0     which of these functions to include, in light of the fact that      GLib/Qt native stubs will probably also exist. - - the invalid messages in the test suite are all useless because  -   they are invalid for the wrong reasons due to protocol changes. -   (Consider extending test suite to validate that they are  -   invalid for right reason, e.g. an "INVALID_ERROR Foo" line  -   in the message files) + - the "break loader" and valid/invalid message tests are all disabled; +   they need to be fixed and re-enabled with the new message args stuff. +   I think I want to drop the .message files thing and just have code +   that generates messages, more like the tests for +   dbus-marshal-recursive.c   - modify the auth protocol to also support other initial-handshake     type of information: @@ -30,26 +30,6 @@ Important for 1.0     since protocol probably modifies the API. But we could have it there     as a safety net. - - re_align_field_recurse() in dbus-message.c is broken because it  -   crashes on some types of header field values. security problem. - - - modify the wire protocol to keep the args signature separate  -   from the args themselves. Make the name of TYPE_CUSTOM part  -   of the type signature, rather than part of the value. -   Then you have the full typecheck in a single string. -   See http://freedesktop.org/pipermail/dbus/2004-June/001169.html - -   Subnote: STRING_OR_NIL is wrong, doesn't work in C++ etc. ; should -   not have done that. Use empty string or special string values or separate functions/signals  -   or whatever instead. - -   Subnote: For recursive types, one approach is that "structs" are done as parens,  -   so e.g. s(ii) is a string and struct { int; int; } etc. Type codes -   then all have to be done as strings not single ints. -   We could also put the type signature for the message body in a -   header field. -   An "any" type has the type string included in the value. -   - need to define bus behavior if you send a message to      yourself; is it an error, or allowed? If allowed,      we need to have a test for it in the test suite. @@ -58,9 +38,12 @@ Important for 1.0     (though they are kind of a pita to pass in as size_t with the       varargs, so maybe not - what does glib do with g_object_get()?) - - it's probably obnoxious that reading/writing bools doesn't return dbus_bool_t;  -   the only possible solution I think is to change dbus_bool_t to unsigned char,  -   but that may cause wackiness elsewhere. + - it's probably obnoxious that reading/writing bools doesn't return +   dbus_bool_t; solution is probably to change bool to 32 bits on the +   wire + + - maybe change and don't align variant bodies to 8-boundary, it uses +   up lots of space in a typical header   - rename the service thing. unique service names (":1") and well-known     ("org.foo.bar") should have different names probably; something like  @@ -68,6 +51,12 @@ Important for 1.0     "application id" for the unique and "common name" or "published     name" for the well-known; not sure yet. + - things are broken now when mixing endianness, because DBusMessage +   doesn't autoswap itself when you access a message of alternate +   endian. + + - add string array support back to append_args() +  Important for 1.0 GLib Bindings  === @@ -103,6 +92,8 @@ Might as Well for 1.0   - connection_open/connection_disconnect lacks symmetry, open/close     or connect/disconnect + - protocol version in each message is pretty silly +  Can Be Post 1.0  === diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index df9ff9d6..e1e387e5 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -308,7 +308,7 @@ handle_introspect (DBusConnection *connection,      g_error ("Out of memory");    dbus_message_append_args (message, -                            DBUS_TYPE_STRING, xml->str, +                            DBUS_TYPE_STRING, &xml->str,                              DBUS_TYPE_INVALID);    dbus_connection_send (connection, message, NULL); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index fe285ab3..24ce6bf3 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -941,8 +941,8 @@ dbus_g_proxy_new_for_service_owner (DBusGConnection          *connection,    DBusGProxy *proxy;    DBusMessage *request, *reply;    DBusError derror; -  char *base_service_name; - +  const char *base_service_name; +      g_return_val_if_fail (connection != NULL, NULL);    g_return_val_if_fail (service_name != NULL, NULL);    g_return_val_if_fail (path_name != NULL, NULL); @@ -962,7 +962,7 @@ dbus_g_proxy_new_for_service_owner (DBusGConnection          *connection,      g_error ("Out of memory");    if (! dbus_message_append_args (request,  -				  DBUS_TYPE_STRING, service_name,  +				  DBUS_TYPE_STRING, &service_name,   				  DBUS_TYPE_INVALID))      g_error ("Out of memory"); @@ -997,7 +997,6 @@ dbus_g_proxy_new_for_service_owner (DBusGConnection          *connection,      dbus_message_unref (request);    if (reply)      dbus_message_unref (reply); -  dbus_free (base_service_name);    return proxy;  } diff --git a/glib/dbus-gutils.c b/glib/dbus-gutils.c index a40e3603..9e4a5cd2 100644 --- a/glib/dbus-gutils.c +++ b/glib/dbus-gutils.c @@ -84,10 +84,10 @@ _dbus_gutils_type_to_string (int type)      {      case DBUS_TYPE_INVALID:        return "invalid"; -    case DBUS_TYPE_NIL: -      return "nil";      case DBUS_TYPE_BOOLEAN:        return "boolean"; +    case DBUS_TYPE_BYTE: +      return "byte";      case DBUS_TYPE_INT32:        return "int32";      case DBUS_TYPE_UINT32: @@ -96,16 +96,20 @@ _dbus_gutils_type_to_string (int type)        return "double";      case DBUS_TYPE_STRING:        return "string"; -    case DBUS_TYPE_CUSTOM: -      return "custom"; +    case DBUS_TYPE_OBJECT_PATH: +      return "object_path"; +    case DBUS_TYPE_SIGNATURE: +      return "signature"; +    case DBUS_TYPE_STRUCT: +      return "struct";      case DBUS_TYPE_ARRAY:        return "array"; -    case DBUS_TYPE_DICT: -      return "dict"; -    case DBUS_TYPE_INT64: -      return "int64"; -    case DBUS_TYPE_UINT64: -      return "uint64"; +    case DBUS_TYPE_VARIANT: +      return "variant"; +    case DBUS_STRUCT_BEGIN_CHAR: +      return "begin_struct"; +    case DBUS_STRUCT_END_CHAR: +      return "end_struct";      default:        return "unknown";      } diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index 04e962fe..b44640ce 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -1,3 +1,26 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gvalue.c GValue to-from DBusMessageIter + * + * Copyright (C) 2004 Ximian, 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-gvalue.h>  gboolean @@ -5,41 +28,43 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)  {    gboolean can_convert = TRUE; +  /* This is slightly evil, we don't use g_value_set_foo() functions */ +#define MAP_BASIC(d_t, g_t)                                     \ +    case DBUS_TYPE_##d_t:                                       \ +      g_value_init (value, G_TYPE_##g_t);                       \ +      dbus_message_iter_get_basic (iter, &value->data[0]);      \ +      break +      switch (dbus_message_iter_get_arg_type (iter))      { -#define MAP(d_t, d_get, g_t, g_set) \ -    case DBUS_##d_t: \ -      g_value_init (value, G_##g_t); \ -      g_value_##g_set (value, dbus_message_iter_##d_get (iter)); \ -      break - -    MAP(TYPE_BYTE, get_byte, TYPE_UCHAR, set_uchar); -    MAP(TYPE_BOOLEAN, get_boolean, TYPE_BOOLEAN , set_boolean); -    MAP(TYPE_INT32, get_int32, TYPE_INT , set_int); -    MAP(TYPE_UINT32, get_uint32, TYPE_UINT , set_uint); -#ifdef DBUS_HAVE_INT64 -    MAP(TYPE_INT64, get_int64, TYPE_INT64 , set_int64); -    MAP(TYPE_UINT64, get_uint64, TYPE_UINT64 , set_uint64); -#endif -    MAP(TYPE_DOUBLE, get_double, TYPE_DOUBLE , set_double); +      MAP_BASIC (BOOLEAN, BOOLEAN); +      MAP_BASIC (BYTE, UCHAR); +      MAP_BASIC (INT32, INT); +      MAP_BASIC (UINT32, UINT); +      MAP_BASIC (INT64, INT64); +      MAP_BASIC (UINT64, UINT64); +      MAP_BASIC (DOUBLE, DOUBLE); +            case DBUS_TYPE_STRING: +    case DBUS_TYPE_OBJECT_PATH: +    case DBUS_TYPE_SIGNATURE:        { -        char *s; /* FIXME use a const string accessor */ +        const char *s;          g_value_init (value, G_TYPE_STRING); -        s = dbus_message_iter_get_string (iter); +        dbus_message_iter_get_basic (iter, &s);          g_value_set_string (value, s); -        g_free (s);        }        break; +       +    case DBUS_TYPE_STRUCT: +    case DBUS_TYPE_ARRAY: +    case DBUS_TYPE_VARIANT:      default: -      /* FIXME: we need to define custom boxed types for arrays -	 etc. so we can map them transparently / pleasantly */        can_convert = FALSE; -      break;      } -#undef MAP +#undef MAP_BASIC    return can_convert;  } @@ -54,59 +79,120 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)    switch (value_type)      {      case G_TYPE_CHAR: -      dbus_message_iter_append_byte (iter, -                                     g_value_get_char (value)); +      { +        char b = g_value_get_char (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_BYTE, +                                             &b)) +          goto nomem; +      }        break;      case G_TYPE_UCHAR: -      dbus_message_iter_append_byte (iter, -                                     g_value_get_uchar (value)); +      { +        unsigned char b = g_value_get_uchar (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_BYTE, +                                             &b)) +          goto nomem; +      }        break;      case G_TYPE_BOOLEAN: -      dbus_message_iter_append_boolean (iter, -                                        g_value_get_boolean (value)); +      { +        unsigned char b = g_value_get_boolean (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_BOOLEAN, +                                             &b)) +          goto nomem; +      }        break;      case G_TYPE_INT: -      dbus_message_iter_append_int32 (iter, -                                      g_value_get_int (value)); +      { +        dbus_int32_t v = g_value_get_int (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_INT32, +                                             &v)) +          goto nomem; +      }        break;      case G_TYPE_UINT: -      dbus_message_iter_append_uint32 (iter, -                                       g_value_get_uint (value)); +      { +        dbus_uint32_t v = g_value_get_uint (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_UINT32, +                                             &v)) +          goto nomem; +      }        break;        /* long gets cut to 32 bits so the remote API is consistent         * on all architectures         */      case G_TYPE_LONG: -      dbus_message_iter_append_int32 (iter, -                                      g_value_get_long (value)); +      { +        dbus_int32_t v = g_value_get_long (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_INT32, +                                             &v)) +          goto nomem; +      }        break;      case G_TYPE_ULONG: -      dbus_message_iter_append_uint32 (iter, -                                       g_value_get_ulong (value)); +      { +        dbus_uint32_t v = g_value_get_ulong (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_UINT32, +                                             &v)) +          goto nomem; +      }        break; -#ifdef DBUS_HAVE_INT64      case G_TYPE_INT64: -      dbus_message_iter_append_int64 (iter, -                                      g_value_get_int64 (value)); +      { +        gint64 v = g_value_get_int64 (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_INT64, +                                             &v)) +          goto nomem; +      }        break;      case G_TYPE_UINT64: -      dbus_message_iter_append_uint64 (iter, -                                       g_value_get_uint64 (value)); +      { +        guint64 v = g_value_get_uint64 (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_UINT64, +                                             &v)) +          goto nomem; +      }        break; -#endif      case G_TYPE_FLOAT: -      dbus_message_iter_append_double (iter, -                                       g_value_get_float (value)); +      { +        double v = g_value_get_float (value); +         +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_DOUBLE, +                                             &v)) +          goto nomem; +      }        break;      case G_TYPE_DOUBLE: -      dbus_message_iter_append_double (iter, -                                       g_value_get_double (value)); +      { +        double v = g_value_get_double (value); +         +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_DOUBLE, +                                             &v)) +          goto nomem; +      }        break;      case G_TYPE_STRING:        /* FIXME, the GValue string may not be valid UTF-8 */ -      dbus_message_iter_append_string (iter, -                                       g_value_get_string (value)); +      { +        const char *v = g_value_get_string (value); +        if (!dbus_message_iter_append_basic (iter, +                                             DBUS_TYPE_STRING, +                                             &v)) +          goto nomem; +      }        break; +            default:        /* FIXME: we need to define custom boxed types for arrays  	 etc. so we can map them transparently / pleasantly */ @@ -115,5 +201,9 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)      }    return can_convert; + + nomem: +  g_error ("no memory"); +  return FALSE;  } diff --git a/qt/message.cpp b/qt/message.cpp index 2c1f35eb..55db3f39 100644 --- a/qt/message.cpp +++ b/qt/message.cpp @@ -185,19 +185,31 @@ QVariant Message::iterator::marshallBaseType( DBusMessageIter* i )    QVariant ret;    switch (dbus_message_iter_get_arg_type(i)) {    case DBUS_TYPE_INT32: -    ret = QVariant( dbus_message_iter_get_int32(i) ); +    { +      dbus_int32_t v; +      dbus_message_iter_get_basic (i, &v); +      ret = QVariant( v ); +    }      break;    case DBUS_TYPE_UINT32: -    ret = QVariant( dbus_message_iter_get_uint32(i) ); +    { +      dbus_uint32_t v; +      dbus_message_iter_get_basic (i, &v); +      ret = QVariant( v ); +    }      break;    case DBUS_TYPE_DOUBLE: -    ret = QVariant( dbus_message_iter_get_double(i) ); +    { +      double v; +      dbus_message_iter_get_basic (i, &v); +      ret = QVariant( v ); +    }      break;    case DBUS_TYPE_STRING:      { -      char *str = dbus_message_iter_get_string(i); -      ret = QVariant( QString::fromLatin1(str) ); -      dbus_free(str); +      const char *v; +      dbus_message_iter_get_basic (i, &v); +      ret = QVariant( v );      }      break;    default: @@ -224,14 +236,16 @@ Message::iterator::fillVar()      switch ( dbus_message_iter_get_array_type( d->iter ) ) {      case DBUS_TYPE_STRING: {        QStringList tempList; -      int count; -      char** charArray; -      dbus_message_iter_get_string_array( d->iter, &charArray, &count ); -      for ( int i=0; i < count; i++ ) { -        tempList.append( QString( charArray[i] ) ); -      } +      DBusMessageIter sub; +      dbus_message_iter_recurse (d->iter, &sub); +      while (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_INVALID) +        { +          const char *v; +          dbus_message_iter_get_basic (&sub, &v); +          tempList.append( QString( v ) ); +          dbus_message_iter_next (&sub); +        }        d->var = QVariant( tempList ); -      dbus_free( charArray );        break;      }      default: @@ -241,6 +255,11 @@ Message::iterator::fillVar()      }      break;    } +#if 0 +  /* DICT is gone for now, but expected to be reintroduced, or else +   * reintroduced as a flag on the introspection data that can +   * apply to array of struct of two fields +   */    case DBUS_TYPE_DICT: {      qDebug( "Got a hash!" );      QMap<QString, QVariant> tempMap; @@ -258,6 +277,7 @@ Message::iterator::fillVar()      d->var = QVariant();      break;    } +#endif    default:      qDebug( "not implemented" );      d->var = QVariant(); @@ -485,49 +505,51 @@ Message::message() const  Message& Message::operator<<( bool b )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_BOOLEAN, b, +  const unsigned char byte = b; +  dbus_message_append_args( d->msg, DBUS_TYPE_BOOLEAN, &byte,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( Q_INT8 byte )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_BYTE, byte, +  dbus_message_append_args( d->msg, DBUS_TYPE_BYTE, &byte,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( Q_INT32 num )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_INT32, num, +  dbus_message_append_args( d->msg, DBUS_TYPE_INT32, &num,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( Q_UINT32 num )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_UINT32, num, +  dbus_message_append_args( d->msg, DBUS_TYPE_UINT32, &num,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( Q_INT64 num )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_INT64, num, +  dbus_message_append_args( d->msg, DBUS_TYPE_INT64, &num,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( Q_UINT64 num )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_UINT64, num, +  dbus_message_append_args( d->msg, DBUS_TYPE_UINT64, &num,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( double num )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_DOUBLE, num, +  dbus_message_append_args( d->msg, DBUS_TYPE_DOUBLE, &num,                              DBUS_TYPE_INVALID );  }  Message& Message::operator<<( const QString& str )  { -  dbus_message_append_args( d->msg, DBUS_TYPE_STRING, str.unicode(), +  const char *u = str.utf8(); +  dbus_message_append_args( d->msg, DBUS_TYPE_STRING, &u,                              DBUS_TYPE_INVALID );  } diff --git a/test/Makefile.am b/test/Makefile.am index 0579e7f8..4498b7e3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -10,7 +10,8 @@ INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)  if DBUS_BUILD_TESTS -TEST_BINARIES=test-service break-loader spawn-test test-segfault test-exit test-sleep-forever +## break-loader removed for now +TEST_BINARIES=test-service spawn-test test-segfault test-exit test-sleep-forever  else  TEST_BINARIES=  endif @@ -28,8 +29,8 @@ test_service_SOURCES=				\  	test-utils.c				\  	test-utils.h -break_loader_SOURCES=				\ -	break-loader.c +##break_loader_SOURCES=				\ +##	break-loader.c  spawn_test_SOURCES=				\  	spawn-test.c @@ -49,7 +50,7 @@ decode_gcov_SOURCES=				\  TEST_LIBS=$(DBUS_TEST_LIBS) $(top_builddir)/dbus/libdbus-convenience.la  test_service_LDADD=$(TEST_LIBS) -break_loader_LDADD= $(TEST_LIBS) +## break_loader_LDADD= $(TEST_LIBS)  spawn_test_LDADD=$(TEST_LIBS)  decode_gcov_LDADD=$(TEST_LIBS) diff --git a/test/break-loader.c b/test/break-loader.c index cb7dc19c..f74d5025 100644 --- a/test/break-loader.c +++ b/test/break-loader.c @@ -36,7 +36,7 @@  #include <dbus/dbus-string.h>  #include <dbus/dbus-internals.h>  #include <dbus/dbus-test.h> -#include <dbus/dbus-marshal.h> +#include <dbus/dbus-marshal-basic.h>  #undef DBUS_COMPILATION  static DBusString failure_dir; diff --git a/test/glib/run-test.sh b/test/glib/run-test.sh index 5d0317a3..473946a9 100755 --- a/test/glib/run-test.sh +++ b/test/glib/run-test.sh @@ -61,9 +61,9 @@ if test x$MODE = xprofile ; then    if test x$PROFILE_TYPE = x ; then        PROFILE_TYPE=all    fi -  $DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-profile $PROFILE_TYPE || die "test-profile failed" +  libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-profile $PROFILE_TYPE || die "test-profile failed"  else -  $DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-dbus-glib || die "test-dbus-glib failed" +  libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-dbus-glib || die "test-dbus-glib failed"  fi  ## we kill -TERM so gcov data can be written out diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index 2315c97c..5ebf3b9d 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -62,8 +62,9 @@ main (int argc, char **argv)    int service_list_len;    int i;    guint32 result; -  char *str; -   +  const char *v_STRING; +  guint32 v_UINT32; +        g_type_init ();    loop = g_main_loop_new (NULL, FALSE); @@ -115,12 +116,14 @@ main (int argc, char **argv)    g_strfreev (service_list);    /* Test handling of unknown method */ +  v_STRING = "blah blah blah blah blah"; +  v_UINT32 = 10;    call = dbus_g_proxy_begin_call (driver, "ThisMethodDoesNotExist", -                                 DBUS_TYPE_STRING, -                                 "blah blah blah blah blah", -                                 DBUS_TYPE_INT32, -                                 10, -                                 DBUS_TYPE_INVALID); +                                  DBUS_TYPE_STRING, +                                  &v_STRING, +                                  DBUS_TYPE_INT32, +                                  &v_UINT32, +                                  DBUS_TYPE_INVALID);    error = NULL;    if (dbus_g_proxy_end_call (driver, call, &error, @@ -135,17 +138,19 @@ main (int argc, char **argv)    g_error_free (error);    /* Activate a service */ +  v_STRING = "org.freedesktop.DBus.TestSuiteEchoService"; +  v_UINT32 = 0;    call = dbus_g_proxy_begin_call (driver, "ActivateService", -                                 DBUS_TYPE_STRING, -                                 "org.freedesktop.DBus.TestSuiteEchoService", -                                 DBUS_TYPE_UINT32, -                                 0, -                                 DBUS_TYPE_INVALID); +                                  DBUS_TYPE_STRING, +                                  &v_STRING, +                                  DBUS_TYPE_UINT32, +                                  &v_UINT32, +                                  DBUS_TYPE_INVALID);    error = NULL;    if (!dbus_g_proxy_end_call (driver, call, &error, -                             DBUS_TYPE_UINT32, &result, -                             DBUS_TYPE_INVALID)) +                              DBUS_TYPE_UINT32, &result, +                              DBUS_TYPE_INVALID))      {        g_printerr ("Failed to complete Activate call: %s\n",                    error->message); @@ -156,12 +161,14 @@ main (int argc, char **argv)    g_print ("Activation of echo service = 0x%x\n", result);    /* Activate a service again */ +  v_STRING = "org.freedesktop.DBus.TestSuiteEchoService"; +  v_UINT32 = 0;    call = dbus_g_proxy_begin_call (driver, "ActivateService", -                                 DBUS_TYPE_STRING, -                                 "org.freedesktop.DBus.TestSuiteEchoService", -                                 DBUS_TYPE_UINT32, -                                 0, -                                 DBUS_TYPE_INVALID); +                                  DBUS_TYPE_STRING, +                                  &v_STRING, +                                  DBUS_TYPE_UINT32, +                                  &v_UINT32, +                                  DBUS_TYPE_INVALID);    error = NULL;    if (!dbus_g_proxy_end_call (driver, call, &error, @@ -192,15 +199,16 @@ main (int argc, char **argv)        exit (1);            } +  v_STRING = "my string hello";    call = dbus_g_proxy_begin_call (proxy, "Echo", -                                 DBUS_TYPE_STRING, -                                 "my string hello", -                                 DBUS_TYPE_INVALID); +                                  DBUS_TYPE_STRING, +                                  &v_STRING, +                                  DBUS_TYPE_INVALID);    error = NULL;    if (!dbus_g_proxy_end_call (proxy, call, &error, -                             DBUS_TYPE_STRING, &str, -                             DBUS_TYPE_INVALID)) +                              DBUS_TYPE_STRING, &v_STRING, +                              DBUS_TYPE_INVALID))      {        g_printerr ("Failed to complete Echo call: %s\n",                    error->message); @@ -208,8 +216,7 @@ main (int argc, char **argv)        exit (1);      } -  g_print ("String echoed = \"%s\"\n", str); -  g_free (str); +  g_print ("String echoed = \"%s\"\n", v_STRING);    /* Test oneway call and signal handling */ diff --git a/test/glib/test-profile.c b/test/glib/test-profile.c index 8e636d0a..55dc603f 100644 --- a/test/glib/test-profile.c +++ b/test/glib/test-profile.c @@ -48,7 +48,7 @@   */  #define N_CLIENT_THREADS 1  /* It seems like at least 750000 or so iterations reduces the variability to sane levels */ -#define N_ITERATIONS 750000 +#define N_ITERATIONS 7500  #define N_PROGRESS_UPDATES 20  /* Don't make PAYLOAD_SIZE too huge because it gets used as a static buffer size */  #define PAYLOAD_SIZE 0 @@ -103,17 +103,19 @@ static void  send_echo_method_call (DBusConnection *connection)  {    DBusMessage *message; +  const char *hello = "Hello World!"; +  dbus_int32_t i32 = 123456;    message = dbus_message_new_method_call (ECHO_SERVICE,                                            ECHO_PATH,                                            ECHO_INTERFACE,                                            ECHO_PING_METHOD);    dbus_message_append_args (message, -                            DBUS_TYPE_STRING, "Hello World!", -                            DBUS_TYPE_INT32, 123456, +                            DBUS_TYPE_STRING, &hello, +                            DBUS_TYPE_INT32, &i32,  #if PAYLOAD_SIZE > 0                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, -                            payload, PAYLOAD_SIZE, +                            &payload, PAYLOAD_SIZE,  #endif                              DBUS_TYPE_INVALID); @@ -277,10 +279,6 @@ no_bus_init_server (ServerData       *sd)  {    DBusServer *server;    DBusError error; -   -#ifndef DBUS_DISABLE_ASSERT -  g_printerr ("You should probably --disable-asserts before you profile as they have noticeable overhead\n"); -#endif    dbus_error_init (&error);    server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, @@ -511,14 +509,6 @@ with_bus_init_server (ServerData       *sd)        g_printerr ("You have to run with_bus mode with the run-test.sh script\n");        exit (1);      } -   -#ifndef DBUS_DISABLE_ASSERT -  g_printerr ("You should probably --disable-asserts before you profile as they have noticeable overhead\n"); -#endif -   -#ifdef DBUS_ENABLE_VERBOSE_MODE -  g_printerr ("You should probably --disable-verbose-mode before you profile as verbose has noticeable overhead\n"); -#endif    /* Note that we use the standard global bus connection for the     * server, and the clients open their own connections so they can @@ -1111,6 +1101,14 @@ main (int argc, char *argv[])    g_thread_init (NULL);    dbus_g_thread_init (); +#ifndef DBUS_DISABLE_ASSERT +  g_printerr ("You should probably --disable-asserts before you profile as they have noticeable overhead\n"); +#endif +   +#if DBUS_ENABLE_VERBOSE_MODE +  g_printerr ("You should probably --disable-verbose-mode before you profile as verbose has noticeable overhead\n"); +#endif +      payload = g_malloc (PAYLOAD_SIZE);    /* The actual size of the DBusMessage on the wire, as of Nov 23 2004, diff --git a/test/glib/test-thread-client.c b/test/glib/test-thread-client.c index 3a370671..07a1b12a 100644 --- a/test/glib/test-thread-client.c +++ b/test/glib/test-thread-client.c @@ -26,18 +26,18 @@ thread_func (gpointer data)        dbus_message_append_iter_init (message, &iter); -      if (!dbus_message_iter_append_int32 (&iter, threadnr)) +      if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &threadnr))  	{  	  g_print ("thread %d: append threadnr failed\n", threadnr);  	} -      if (!dbus_message_iter_append_uint32 (&iter, counter)) +      if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &counter))  	{  	  g_print ("thread %d: append counter (%d) failed\n", threadnr, counter);  	}        str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); -      if (!dbus_message_iter_append_string (&iter, str)) +      if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str))  	{  	  g_print ("thread %d: append string (%s) failed\n", threadnr, str);  	} diff --git a/test/glib/test-thread-server.c b/test/glib/test-thread-server.c index 3d8a3544..e61e3a6a 100644 --- a/test/glib/test-thread-server.c +++ b/test/glib/test-thread-server.c @@ -34,7 +34,8 @@ filter_test_message (DBusConnection     *connection,    DBusMessageIter iter;    gint32 threadnr;    guint32 counter; -  char *str, *expected_str; +  const char *str; +  char *expected_str;    GString *counter_str;    int i; @@ -49,7 +50,7 @@ filter_test_message (DBusConnection     *connection,        g_print ("First arg not right type\n");        goto out;      } -  threadnr = dbus_message_iter_get_int32 (&iter); +   dbus_message_iter_get_basic (&iter, &threadnr);    if (threadnr < 0 || threadnr >= N_TEST_THREADS)      {        g_print ("Invalid thread nr\n"); @@ -68,7 +69,7 @@ filter_test_message (DBusConnection     *connection,        goto out;      } -  counter = dbus_message_iter_get_uint32 (&iter); +   dbus_message_iter_get_basic (&iter, &counter);    if (counter != data->counters[threadnr])      { @@ -89,7 +90,7 @@ filter_test_message (DBusConnection     *connection,        goto out;      } -  str = dbus_message_iter_get_string (&iter); +  dbus_message_iter_get_basic (&iter, &str);    if (str == NULL)      { @@ -103,7 +104,6 @@ filter_test_message (DBusConnection     *connection,        g_print ("Wrong string '%s', expected '%s'\n", str, expected_str);        goto out;      } -  g_free (str);    g_free (expected_str);    if (dbus_message_iter_next (&iter)) diff --git a/test/test-service.c b/test/test-service.c index cb4ff582..3ba16bbf 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -58,7 +58,7 @@ handle_echo (DBusConnection     *connection,      die ("No memory\n");    if (!dbus_message_append_args (reply, -                                 DBUS_TYPE_STRING, s, +                                 DBUS_TYPE_STRING, &s,                                   DBUS_TYPE_INVALID))      die ("No memory"); @@ -67,8 +67,6 @@ handle_echo (DBusConnection     *connection,    fprintf (stderr, "Echo service echoed string: \"%s\"\n", s); -  dbus_free (s); -      dbus_message_unref (reply);    return DBUS_HANDLER_RESULT_HANDLED; @@ -104,6 +102,7 @@ path_message_func (DBusConnection  *connection,      {        /* Emit the Foo signal */        DBusMessage *signal; +      double v_DOUBLE;        _dbus_verbose ("emitting signal Foo\n"); @@ -112,9 +111,10 @@ path_message_func (DBusConnection  *connection,                                          "Foo");        if (signal == NULL)          die ("No memory\n"); -       + +      v_DOUBLE = 42.6;        if (!dbus_message_append_args (signal, -                                     DBUS_TYPE_DOUBLE, 42.6, +                                     DBUS_TYPE_DOUBLE, &v_DOUBLE,                                       DBUS_TYPE_INVALID))          die ("No memory"); diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c index 43c41c73..572a1d14 100644 --- a/tools/dbus-print-message.c +++ b/tools/dbus-print-message.c @@ -84,7 +84,7 @@ print_message (DBusMessage *message)    do      {        int type = dbus_message_iter_get_arg_type (&iter); -      char *str; +      const char *str;        dbus_uint32_t uint32;        dbus_int32_t int32;        double d; @@ -97,32 +97,32 @@ print_message (DBusMessage *message)        switch (type)  	{  	case DBUS_TYPE_STRING: -	  str = dbus_message_iter_get_string (&iter); +          dbus_message_iter_get_basic (&iter, &str);  	  printf ("string:%s\n", str);  	  break;  	case DBUS_TYPE_INT32: -	  int32 = dbus_message_iter_get_int32 (&iter); +          dbus_message_iter_get_basic (&iter, &int32);  	  printf ("int32:%d\n", int32);  	  break;  	case DBUS_TYPE_UINT32: -	  uint32 = dbus_message_iter_get_uint32 (&iter); +          dbus_message_iter_get_basic (&iter, &uint32);  	  printf ("int32:%u\n", uint32);  	  break;  	case DBUS_TYPE_DOUBLE: -	  d = dbus_message_iter_get_double (&iter); +	  dbus_message_iter_get_basic (&iter, &d);  	  printf ("double:%f\n", d);  	  break;  	case DBUS_TYPE_BYTE: -	  byte = dbus_message_iter_get_byte (&iter); +	  dbus_message_iter_get_basic (&iter, &byte);  	  printf ("byte:%d\n", byte);  	  break;  	case DBUS_TYPE_BOOLEAN: -	  boolean = dbus_message_iter_get_boolean (&iter); +          dbus_message_iter_get_basic (&iter, &boolean);  	  printf ("boolean:%s\n", boolean ? "true" : "false");  	  break; diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 81ecac7e..67411b46 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -215,33 +215,39 @@ main (int argc, char *argv[])  	{  	case DBUS_TYPE_BYTE:  	  byte = strtoul (c, NULL, 0); -	  dbus_message_iter_append_byte (&iter, byte); +	  dbus_message_iter_append_basic (&iter, DBUS_TYPE_BYTE, &byte);  	  break;  	case DBUS_TYPE_DOUBLE:  	  d = strtod (c, NULL); -	  dbus_message_iter_append_double (&iter, d); +	  dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &d);  	  break;  	case DBUS_TYPE_INT32:  	  int32 = strtol (c, NULL, 0); -	  dbus_message_iter_append_int32 (&iter, int32); +	  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &int32);  	  break;  	case DBUS_TYPE_UINT32:  	  uint32 = strtoul (c, NULL, 0); -	  dbus_message_iter_append_uint32 (&iter, uint32); +	  dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &uint32);  	  break;  	case DBUS_TYPE_STRING: -	  dbus_message_iter_append_string (&iter, c); +	  dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &c);  	  break;  	case DBUS_TYPE_BOOLEAN:            if (strcmp(c, "true") == 0) -            dbus_message_iter_append_boolean (&iter, TRUE); +            { +              byte = TRUE; +              dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &c); +            }  	  else if (strcmp(c, "false") == 0) -            dbus_message_iter_append_boolean (&iter, FALSE); +            { +              byte = FALSE; +              dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &c); +            }  	  else  	    {  	      fprintf (stderr, "%s: Expected \"true\" or \"false\" instead of \"%s\"\n", argv[0], c);  | 
