dbus/dbus dbus-marshal-basic.c, NONE, 1.1 dbus-marshal-basic.h, NONE, 1.1 dbus-marshal-recursive.c, NONE, 1.1 dbus-marshal-recursive.h, NONE, 1.1 dbus-protocol-new.h, NONE, 1.1

Havoc Pennington hp at freedesktop.org
Sat Dec 18 16:11:51 PST 2004


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

Added Files:
	dbus-marshal-basic.c dbus-marshal-basic.h 
	dbus-marshal-recursive.c dbus-marshal-recursive.h 
	dbus-protocol-new.h 
Log Message:
back up some files I'm working on that don't do anything yet


--- NEW FILE: dbus-marshal-basic.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-marshal-basic.c  Marshalling routines for basic (primitive) types
 *
 * 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-basic.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.
 *
 * A signature is just a string with multiple types one after the other.
 * for example a type is "i" or "(ii)", a signature is "i(ii)"
 * where i is int and (ii) is struct { int; int; }
 *
 * @{
 */

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 */

--- NEW FILE: dbus-marshal-basic.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-marshal-basic.h  Marshalling routines for basic (primitive) types
 *
 * Copyright (C) 2002  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_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

/****************************************************** Remove later */
#undef DBUS_TYPE_INVALID
#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')

/* Primitive types */
#define DBUS_TYPE_BYTE          ((int) 'y')
#define DBUS_TYPE_BOOLEAN       ((int) 'b')
#define DBUS_TYPE_INT32         ((int) 'i')

#define DBUS_TYPE_UINT32        ((int) 'u')
#define DBUS_TYPE_INT64         ((int) 'x')
#define DBUS_TYPE_UINT64        ((int) 't')

#define DBUS_TYPE_DOUBLE        ((int) 'd')
#define DBUS_TYPE_STRING        ((int) 's')
#define DBUS_TYPE_OBJECT_PATH   ((int) 'o')

/* Compound types */
#define DBUS_TYPE_ARRAY         ((int) 'a')
#define DBUS_TYPE_DICT          ((int) 'm')
#define DBUS_TYPE_VARIANT       ((int) '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')

/* 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_END_CHAR     ((int) ')')
#define DBUS_NAME_DELIMITER_CHAR ((int) '\'')
/****************************************************** Remove later */

#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 */

--- NEW FILE: dbus-marshal-recursive.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-marshal-recursive.c  Marshalling routines for recursive types
 *
 * Copyright (C) 2004 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "dbus-marshal-recursive.h"
#include "dbus-internals.h"

/**
 * @addtogroup DBusMarshal
 * @{
 */

void
_dbus_type_reader_init (DBusTypeReader    *reader,
                        int                byte_order,
                        const DBusString  *type_str,
                        int                type_pos,
                        const DBusString  *value_str,
                        int                value_pos)
{
     

}

int
_dbus_type_reader_get_value_end (DBusTypeReader    *reader)
{


}

int
_dbus_type_reader_get_type_end (DBusTypeReader    *reader)
{


}

int
_dbus_type_reader_get_current_type (DBusTypeReader *reader)
{


}

int
_dbus_type_reader_get_array_type (DBusTypeReader    *reader)
{


}

void
_dbus_type_reader_read_basic (DBusTypeReader    *reader,
                              void              *value)
{


}

dbus_bool_t
_dbus_type_reader_read_array (DBusTypeReader    *reader,
                              int                type,
                              void             **array,
                              int               *array_len)
{


}

void
_dbus_type_reader_recurse (DBusTypeReader    *reader)
{


}

void
_dbus_type_reader_unrecurse (DBusTypeReader    *reader)
{


}

dbus_bool_t
_dbus_type_reader_next (DBusTypeReader    *reader)
{



}

void
_dbus_type_writer_init (DBusTypeWriter *writer,
                        int             byte_order,
                        DBusString     *type_str,
                        int             type_pos,
                        DBusString     *value_str,
                        int             value_pos)
{


}

dbus_bool_t
_dbus_type_writer_write_basic (DBusTypeWriter *writer,
                               int             type,
                               const void     *value)
{


}

dbus_bool_t
_dbus_type_writer_write_array (DBusTypeWriter *writer,
                               int             type,
                               const void     *array,
                               int             array_len)
{


}

dbus_bool_t
_dbus_type_writer_recurse (DBusTypeWriter *writer,
                           int             container_type)
{


}

dbus_bool_t
_dbus_type_writer_unrecurse (DBusTypeWriter *writer)
{


}

/** @} */ /* end of DBusMarshal group */

#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
  DBusString signature;
  DBusString body;
} DataBlock;

typedef struct
{
  int saved_sig_len;
  int saved_body_len;
} DataBlockState;

static dbus_bool_t
data_block_init (DataBlock *block)
{
  if (!_dbus_string_init (&block->signature))
    return FALSE;

  if (!_dbus_string_init (&block->body))
    {
      _dbus_string_free (&block->signature);
      return FALSE;
    }
  
  return TRUE;
}

static void
data_block_free (DataBlock *block)
{
  _dbus_string_free (&block->signature);
  _dbus_string_free (&block->body);
}

static void
data_block_save (DataBlock      *block,
                 DataBlockState *state)
{
  state->saved_sig_len = _dbus_string_get_length (&block->signature);
  state->saved_body_len = _dbus_string_get_length (&block->body);
}

static void
data_block_restore (DataBlock      *block,
                    DataBlockState *state)
{
  /* These set_length should be shortening things so should always work */
  
  if (!_dbus_string_set_length (&block->signature,
                                state->saved_sig_len))
    _dbus_assert_not_reached ("could not restore signature length");
  
  if (!_dbus_string_set_length (&block->body,
                                state->saved_body_len))
    _dbus_assert_not_reached ("could not restore body length");
}

static void
data_block_init_reader_writer (DataBlock      *block,
                               int             byte_order,
                               DBusTypeReader *reader,
                               DBusTypeWriter *writer)
{
  _dbus_type_reader_init (reader,
                          byte_order,
                          &block->signature,
                          _dbus_string_get_length (&block->signature),
                          &block->body,
                          _dbus_string_get_length (&block->body));
  
  _dbus_type_writer_init (writer,
                          byte_order,
                          &block->signature,
                          _dbus_string_get_length (&block->signature),
                          &block->body,
                          _dbus_string_get_length (&block->body));
}

#define SAMPLE_INT32           12345678
#define SAMPLE_INT32_ALTERNATE 53781429
static dbus_bool_t
write_int32 (DataBlock      *block,
             DBusTypeWriter *writer)
{
  dbus_int32_t v = SAMPLE_INT32;

  return _dbus_type_writer_write_basic (writer,
                                        DBUS_TYPE_INT32,
                                        &v);
}

static void
check_expected_type (DBusTypeReader *reader,
                     int             expected)
{
  int t;

  t = _dbus_type_reader_get_current_type (reader);
  
  if (t != expected)
    {
      _dbus_warn ("Read type %s while expecting %s\n",
                  _dbus_type_to_string (t),
                  _dbus_type_to_string (expected));
      exit (1);
    }
}

static dbus_bool_t
read_int32 (DataBlock      *block,
            DBusTypeReader *reader)
{
  dbus_int32_t v;

  check_expected_type (reader, DBUS_TYPE_INT32);
  
  _dbus_type_reader_read_basic (reader,
                                (dbus_int32_t*) &v);

  _dbus_assert (v == SAMPLE_INT32);

  return TRUE;
}

static dbus_bool_t
write_struct_with_int32s (DataBlock      *block,
                          DBusTypeWriter *writer)
{
  dbus_int32_t v;
  DataBlockState saved;

  data_block_save (block, &saved);
  
  if (!_dbus_type_writer_recurse (writer,
                                  DBUS_TYPE_STRUCT))
    return FALSE;

  v = SAMPLE_INT32;
  if (!_dbus_type_writer_write_basic (writer,
                                      DBUS_TYPE_INT32,
                                      &v))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }

  v = SAMPLE_INT32_ALTERNATE;
  if (!_dbus_type_writer_write_basic (writer,
                                      DBUS_TYPE_INT32,
                                      &v))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }

  if (!_dbus_type_writer_unrecurse (writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  
  return TRUE;
}

static dbus_bool_t
read_struct_with_int32s (DataBlock      *block,
                         DBusTypeReader *reader)
{
  dbus_int32_t v;

  check_expected_type (reader, DBUS_TYPE_STRUCT);
  
  _dbus_type_reader_recurse (reader);

  check_expected_type (reader, DBUS_TYPE_INT32);
  
  _dbus_type_reader_read_basic (reader,
                                (dbus_int32_t*) &v);

  _dbus_assert (v == SAMPLE_INT32);

  _dbus_type_reader_next (reader);
  check_expected_type (reader, DBUS_TYPE_INT32);
  
  _dbus_type_reader_read_basic (reader,
                                (dbus_int32_t*) &v);

  _dbus_assert (v == SAMPLE_INT32_ALTERNATE);

  _dbus_type_reader_unrecurse (reader);
  
  return TRUE;
}

static dbus_bool_t
write_struct_of_structs (DataBlock      *block,
                         DBusTypeWriter *writer)
{
  DataBlockState saved;

  data_block_save (block, &saved);
  
  if (!_dbus_type_writer_recurse (writer,
                                  DBUS_TYPE_STRUCT))
    return FALSE;

  if (!write_struct_with_int32s (block, writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  if (!write_struct_with_int32s (block, writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  if (!write_struct_with_int32s (block, writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }

  if (!_dbus_type_writer_unrecurse (writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  
  return TRUE;
}

static dbus_bool_t
read_struct_of_structs (DataBlock      *block,
                        DBusTypeReader *reader)
{
  check_expected_type (reader, DBUS_TYPE_STRUCT);
  
  _dbus_type_reader_recurse (reader);

  if (!read_struct_with_int32s (block, reader))
    return FALSE;
  _dbus_type_reader_next (reader);
  if (!read_struct_with_int32s (block, reader))
    return FALSE;
  _dbus_type_reader_next (reader);
  if (!read_struct_with_int32s (block, reader))
    return FALSE;

  _dbus_type_reader_unrecurse (reader);
  
  return TRUE;
}

static dbus_bool_t
write_struct_of_structs_of_structs (DataBlock      *block,
                                    DBusTypeWriter *writer)
{
  DataBlockState saved;

  data_block_save (block, &saved);
  
  if (!_dbus_type_writer_recurse (writer,
                                  DBUS_TYPE_STRUCT))
    return FALSE;

  if (!write_struct_of_structs (block, writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  if (!write_struct_of_structs (block, writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }

  if (!_dbus_type_writer_unrecurse (writer))
    {
      data_block_restore (block, &saved);
      return FALSE;
    }
  
  return TRUE;
}

static dbus_bool_t
read_struct_of_structs_of_structs (DataBlock      *block,
                                   DBusTypeReader *reader)
{
  check_expected_type (reader, DBUS_TYPE_STRUCT);
  
  _dbus_type_reader_recurse (reader);

  if (!read_struct_of_structs (block, reader))
    return FALSE;
  _dbus_type_reader_next (reader);
  if (!read_struct_of_structs (block, reader))
    return FALSE;

  _dbus_type_reader_unrecurse (reader);
  
  return TRUE;
}

typedef enum {
  ITEM_INVALID = -1,
  ITEM_INT32 = 0,
  ITEM_STRUCT_WITH_INT32S,
  ITEM_STRUCT_OF_STRUCTS,
  ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
  ITEM_LAST
} WhichItem;


typedef dbus_bool_t (* WriteItemFunc) (DataBlock      *block,
                                       DBusTypeWriter *writer);
typedef dbus_bool_t (* ReadItemFunc)  (DataBlock      *block,
                                       DBusTypeReader *reader);

typedef struct
{
  WhichItem which;
  WriteItemFunc write_item_func;
  ReadItemFunc read_item_func;
} CheckMarshalItem;

static CheckMarshalItem items[] = {
  { ITEM_INT32, write_int32, read_int32 },
  { ITEM_STRUCT_WITH_INT32S, write_struct_with_int32s, read_struct_with_int32s },
  { ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
  { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
    write_struct_of_structs_of_structs,
    read_struct_of_structs_of_structs }
};

typedef struct
{
  /* Array of items in the above items[]; -1 terminated */
  int items[20];
} TestRun;

static TestRun runs[] = {
  { { ITEM_INVALID } },

  /* INT32 */
  { { ITEM_INT32, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },

  /* STRUCT_WITH_INT32S */
  { { ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
  { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
  { { ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },

  /* STRUCT_OF_STRUCTS */
  { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },

  /* STRUCT_OF_STRUCTS_OF_STRUCTS */
  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }
  
};

static dbus_bool_t
perform_one_run (DataBlock *block,
                 int        byte_order,
                 TestRun   *run)
{
  DBusTypeReader reader;
  DBusTypeWriter writer;
  int i;
  DataBlockState saved;
  dbus_bool_t retval;

  retval = FALSE;

  data_block_save (block, &saved);
  
  data_block_init_reader_writer (block, 
                                 byte_order,
                                 &reader, &writer);

  i = 0;
  while (run->items[i] != ITEM_INVALID)
    {
      CheckMarshalItem *item = &items[run->items[i]];
      if (!(* item->write_item_func) (block, &writer))
        goto out;
      ++i;
    }

  i = 0;
  while (run->items[i] != ITEM_INVALID)
    {
      CheckMarshalItem *item = &items[run->items[i]];
      
      if (!(* item->read_item_func) (block, &reader))
        goto out;

      _dbus_type_reader_next (&reader);
      
      ++i;
    }
  
  retval = TRUE;
  
 out:
  data_block_restore (block, &saved);
  return retval;
}

static dbus_bool_t
perform_all_runs (int byte_order,
                  int initial_offset)
{
  int i;
  DataBlock block;
  dbus_bool_t retval;

  retval = FALSE;
  
  if (!data_block_init (&block))
    return FALSE;

  if (!_dbus_string_lengthen (&block.signature, initial_offset))
    goto out;
  
  if (!_dbus_string_lengthen (&block.body, initial_offset))
    goto out;
  
  i = 0;
  while (i < _DBUS_N_ELEMENTS (runs))
    {
      if (!perform_one_run (&block, byte_order, &runs[i]))
        goto out;
      
      ++i;
    }

  retval = TRUE;
  
 out:
  data_block_free (&block);
  
  return retval;
}

static dbus_bool_t
perform_all_items (int byte_order,
                   int initial_offset)
{
  int i;
  DataBlock block;
  dbus_bool_t retval;
  TestRun run;

  retval = FALSE;
  
  if (!data_block_init (&block))
    return FALSE;


  if (!_dbus_string_lengthen (&block.signature, initial_offset))
    goto out;
  
  if (!_dbus_string_lengthen (&block.body, initial_offset))
    goto out;

  /* Create a run containing all the items */
  i = 0;
  while (i < _DBUS_N_ELEMENTS (items))
    {
      _dbus_assert (i == items[i].which);
      
      run.items[i] = items[i].which;
      
      ++i;
    }
  
  run.items[i] = ITEM_INVALID;

  if (!perform_one_run (&block, byte_order, &run))
    goto out;  
  
  retval = TRUE;
  
 out:
  data_block_free (&block);
  
  return retval;
}

static dbus_bool_t
recursive_marshal_test_iteration (void *data)
{
  int i;

  i = 0;
  while (i < 18)
    {
      if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
        return FALSE;
      if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
        return FALSE;
      if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
        return FALSE;
      if (!perform_all_items (DBUS_BIG_ENDIAN, i))
        return FALSE;
      
      ++i;
    }

  return TRUE;
}

dbus_bool_t _dbus_marshal_recursive_test (void);

dbus_bool_t
_dbus_marshal_recursive_test (void)
{
  _dbus_test_oom_handling ("recursive marshaling",
                           recursive_marshal_test_iteration,
                           NULL);  
  
  return TRUE;
}

#if 1
int
main (int argc, char **argv)
{
  _dbus_marshal_recursive_test ();

  return 0;
}
#endif /* main() */

#endif /* DBUS_BUILD_TESTS */

--- NEW FILE: dbus-marshal-recursive.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-marshal-recursive.h  Marshalling routines for recursive types
 *
 * Copyright (C) 2004 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef DBUS_MARSHAL_RECURSIVE_H
#define DBUS_MARSHAL_RECURSIVE_H

#include <config.h>
#include <dbus/dbus-marshal-basic.h>

#ifndef PACKAGE
#error "config.h not included here"
#endif

/* Notes on my plan to implement this:
 * - also have DBusTypeWriter (heh)
 * - TypeReader has accessors for:
 *    . basic type
 *    . array of basic type (efficiency hack)
 *    . another type reader
 * - a dict will appear to be a list of string, whatever, string, whatever
 * - a variant will contain another TypeReader
 * - a struct will be a list of whatever, whatever, whatever
 *
 * So the basic API usage is to go next, next, next; if the
 * item is a basic type or basic array then read the item;
 * if it's another type reader then process it; if it's
 * a container type (struct, array, variant, dict) then
 * recurse.
 * 
 */

struct DBusTypeReader
{
  int byte_order;
  const DBusString *type_str;
  int type_pos;
  const DBusString *value_str;
  int value_pos;
};

typedef struct DBusTypeReader DBusTypeReader;

struct DBusTypeWriter
{
  int byte_order;
  DBusString *type_str;
  int type_pos;
  DBusString *value_str;
  int value_pos;
};

typedef struct DBusTypeWriter DBusTypeWriter;

void        _dbus_type_reader_init             (DBusTypeReader    *reader,
                                                int                byte_order,
                                                const DBusString  *type_str,
                                                int                type_pos,
                                                const DBusString  *value_str,
                                                int                value_pos);
int         _dbus_type_reader_get_value_end    (DBusTypeReader    *reader);
int         _dbus_type_reader_get_type_end     (DBusTypeReader    *reader);
int         _dbus_type_reader_get_current_type (DBusTypeReader    *reader);
int         _dbus_type_reader_get_array_type   (DBusTypeReader    *reader);
void        _dbus_type_reader_read_basic       (DBusTypeReader    *reader,
                                                void              *value);
dbus_bool_t _dbus_type_reader_read_array       (DBusTypeReader    *reader,
                                                int                type,
                                                void             **array,
                                                int               *array_len);
void        _dbus_type_reader_recurse          (DBusTypeReader    *reader);
void        _dbus_type_reader_unrecurse        (DBusTypeReader    *reader);
dbus_bool_t _dbus_type_reader_next             (DBusTypeReader    *reader);


void        _dbus_type_writer_init        (DBusTypeWriter *writer,
                                           int             byte_order,
                                           DBusString     *type_str,
                                           int             type_pos,
                                           DBusString     *value_str,
                                           int             value_pos);
dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer,
                                           int             type,
                                           const void     *value);
dbus_bool_t _dbus_type_writer_write_array (DBusTypeWriter *writer,
                                           int             type,
                                           const void     *array,
                                           int             array_len);
dbus_bool_t _dbus_type_writer_recurse     (DBusTypeWriter *writer,
                                           int             container_type);
dbus_bool_t _dbus_type_writer_unrecurse   (DBusTypeWriter *writer);

#endif /* DBUS_MARSHAL_RECURSIVE_H */

--- NEW FILE: dbus-protocol-new.h ---
/* -*- 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')

/* Primitive types */
#define DBUS_TYPE_BYTE          ((int) 'y')
#define DBUS_TYPE_BOOLEAN       ((int) 'b')
#define DBUS_TYPE_INT32         ((int) 'i')

#define DBUS_TYPE_UINT32        ((int) 'u')
#define DBUS_TYPE_INT64         ((int) 'x')
#define DBUS_TYPE_UINT64        ((int) 't')

#define DBUS_TYPE_DOUBLE        ((int) 'd')
#define DBUS_TYPE_STRING        ((int) 's')
#define DBUS_TYPE_OBJECT_PATH   ((int) 'o')

/* Compound types */
#define DBUS_TYPE_ARRAY         ((int) 'a')
#define DBUS_TYPE_DICT          ((int) 'm')
#define DBUS_TYPE_VARIANT       ((int) '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')

/* 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_END_CHAR     ((int) ')')
#define DBUS_NAME_DELIMITER_CHAR ((int) '\'')

/* Max length in bytes of a service or interface or member name */
#define DBUS_MAXIMUM_NAME_LENGTH 256

/* Max length of a match rule string */
#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024

/* 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 */



More information about the dbus-commit mailing list