From 305a8d4d988a1011982e284e358165d3368067cc Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 19 Dec 2004 00:11:49 +0000 Subject: back up some files I'm working on that don't do anything yet --- dbus/dbus-marshal-basic.c | 2945 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2945 insertions(+) create mode 100644 dbus/dbus-marshal-basic.c (limited to 'dbus/dbus-marshal-basic.c') diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c new file mode 100644 index 00000000..76477279 --- /dev/null +++ b/dbus/dbus-marshal-basic.c @@ -0,0 +1,2945 @@ +/* -*- 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 + +/** + * @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 + +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 */ -- cgit