2005-01-17 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-message-builder.c
index 03022ba..83b37af 100644 (file)
@@ -1,9 +1,9 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-message-builder.c Build messages from text files for testing (internal to D-BUS implementation)
  * 
- * Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003, 2004 Red Hat, Inc.
  *
- * Licensed under the Academic Free License version 1.2
+ * 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
  * @{
  */
 
+/**
+ * Saved length
+ */
 typedef struct
 {
-  DBusString name;
+  DBusString name; /**< Name of the length */
   int start;  /**< Calculate length since here */
   int length; /**< length to write */
   int offset; /**< where to write it into the data */
@@ -67,8 +70,8 @@ ensure_saved_length (DBusHashTable    *hash,
 {
   SavedLength *sl;
   const char *s;
-
-  _dbus_string_get_const_data (name, &s);
+  
+  s = _dbus_string_get_const_data (name);
 
   sl = _dbus_hash_table_lookup_string (hash, s);
   if (sl != NULL)
@@ -76,7 +79,7 @@ ensure_saved_length (DBusHashTable    *hash,
   
   sl = dbus_new0 (SavedLength, 1);
 
-  if (!_dbus_string_init (&sl->name, _DBUS_INT_MAX))
+  if (!_dbus_string_init (&sl->name))
     {
       dbus_free (sl);
       return NULL;
@@ -85,7 +88,7 @@ ensure_saved_length (DBusHashTable    *hash,
   if (!_dbus_string_copy (name, 0, &sl->name, 0))
     goto failed;
 
-  _dbus_string_get_const_data (&sl->name, &s);
+  s = _dbus_string_get_const_data (&sl->name);
 
   if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
     goto failed;
@@ -265,6 +268,369 @@ append_saved_length (DBusString       *dest,
   return TRUE;
 }
 
+static int
+message_type_from_string (const DBusString *str,
+                          int               start)
+{
+  const char *s;
+
+  s = _dbus_string_get_const_data_len (str, start,
+                                       _dbus_string_get_length (str) - start);
+
+  if (strncmp (s, "method_call", strlen ("method_call")) == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_CALL;
+  else if (strncmp (s, "method_return", strlen ("method_return")) == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_RETURN;
+  else if (strncmp (s, "signal", strlen ("signal")) == 0)
+    return DBUS_MESSAGE_TYPE_SIGNAL;
+  else if (strncmp (s, "error", strlen ("error")) == 0)
+    return DBUS_MESSAGE_TYPE_ERROR;
+  else if (strncmp (s, "invalid", strlen ("invalid")) == 0)
+    return DBUS_MESSAGE_TYPE_INVALID;
+  else
+    return -1;
+}
+
+static dbus_bool_t
+append_string_field (DBusString *dest,
+                     int         endian,
+                     int         field,
+                     int         type,
+                     const char *value)
+{
+  int len;
+  
+  if (!_dbus_string_append_byte (dest, field))
+    {
+      _dbus_warn ("couldn't append field name byte\n");
+      return FALSE;
+    }
+  
+  if (!_dbus_string_append_byte (dest, type))
+    {
+      _dbus_warn ("could not append typecode byte\n");
+      return FALSE;
+    }
+
+  len = strlen (value);
+
+  if (!_dbus_marshal_uint32 (dest, endian, len))
+    {
+      _dbus_warn ("couldn't append string length\n");
+      return FALSE;
+    }
+  
+  if (!_dbus_string_append (dest, value))
+    {
+      _dbus_warn ("couldn't append field value\n");
+      return FALSE;
+    }
+
+  if (!_dbus_string_append_byte (dest, 0))
+    {
+      _dbus_warn ("couldn't append string nul term\n");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+#ifdef DBUS_BUILD_TESTS
+/**
+ * Parses a basic type defined by type contained in a DBusString. The
+ * end_return parameter may be #NULL if you aren't interested in it. The
+ * type is parsed and stored in value_return. Return parameters are not
+ * initialized if the function returns #FALSE.
+ *
+ * @param str the string
+ * @param type the type of the basic type
+ * @param start the byte index of the start of the type
+ * @param value_return return location of the value or #NULL
+ * @param end_return return location of the end of the type, or #NULL
+ * @returns #TRUE on success
+ */
+static dbus_bool_t
+_dbus_string_parse_basic_type (const DBusString  *str,
+                              char               type,
+                              int                start,
+                              void              *value,
+                              int               *end_return)
+{
+  int end = start;
+
+  switch (type)
+    {
+    case DBUS_TYPE_BOOLEAN:
+      {
+       int len = _dbus_string_get_length (str) - start;
+       if (len >= 5 && _dbus_string_find_to (str, start, start + 5, "false", NULL))
+         {
+           end += 5;
+           *(unsigned char *) value = TRUE;
+         }
+       else if (len >= 4 && _dbus_string_find_to (str, start, start + 4, "true", NULL))
+         {
+           end += 4;
+           *(unsigned char *) value = FALSE;
+         }
+       else
+         _dbus_warn ("could not parse BOOLEAN\n");
+       break;
+      }
+    case DBUS_TYPE_BYTE:
+      {
+       long val = 0;
+
+       if (_dbus_string_get_byte (str, start) == '\'' &&
+           _dbus_string_get_length (str) >= start + 4 &&
+           _dbus_string_get_byte (str, start + 1) == '\\' &&
+           _dbus_string_get_byte (str, start + 2) == '\'' &&
+           _dbus_string_get_byte (str, start + 3) == '\'')
+         {
+           val = '\'';
+           end += 4;
+         }
+       else if (_dbus_string_get_byte (str, start) == '\'' &&
+                _dbus_string_get_length (str) >= start + 3 &&
+                _dbus_string_get_byte (str, start + 2) == '\'')
+         {
+           val = _dbus_string_get_byte (str, start + 1);
+           end += 3;
+         }
+       else
+         {
+           if (!_dbus_string_parse_int (str, start, &val, &end)) 
+             _dbus_warn ("Failed to parse integer for BYTE\n");
+         }
+
+       if (val > 255)
+         _dbus_warn ("A byte must be in range 0-255 not %ld\n", val);
+
+       *(unsigned char *) value = val;
+       break;
+      }
+    case DBUS_TYPE_INT32:
+      {
+       long val;
+       if (_dbus_string_parse_int (str, start, &val, &end))
+         *(dbus_int32_t *)value = val;
+       break;
+      }
+    case DBUS_TYPE_UINT32:
+      {
+       unsigned long val;
+       if (_dbus_string_parse_uint (str, start, &val, &end))
+         *(dbus_uint32_t *)value = val;
+       break;
+      }
+#ifdef DBUS_HAVE_INT64
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64: 
+      /* use stroll oull */
+      _dbus_assert_not_reached ("string -> [u]int64 not supported yet");
+      break;
+#endif /* DBUS_HAVE_INT64 */
+    case DBUS_TYPE_DOUBLE:
+      _dbus_string_parse_double (str, start, value, &end);
+      break;
+    default:
+      _dbus_assert_not_reached ("not a basic type");
+      break;
+    }
+  if (end_return)
+    *end_return = end;
+
+  return end != start;
+}
+#endif /* DBUS_BUILD_TESTS */
+
+static dbus_bool_t
+parse_basic_type (DBusString *src, char type,
+                 DBusString *dest, dbus_bool_t *unalign,
+                 int endian)
+{
+  int align;
+  int align_pad_start, align_pad_end;
+  unsigned char data[16];
+
+  switch (type)
+    {
+    case DBUS_TYPE_BYTE:
+      align = 1;
+      break;
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT32:
+      align = 4;
+      break;
+    case DBUS_TYPE_DOUBLE:
+      align = 8;
+      break;
+    default:
+      _dbus_assert_not_reached ("not a basic type");
+      break;
+    }
+
+  align_pad_start = _dbus_string_get_length (dest);
+  align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, align);
+
+  _dbus_string_delete_first_word (src);
+
+  if (!_dbus_string_parse_basic_type (src, type, 0, data, NULL))
+    {
+      _dbus_verbose ("failed to parse type '%c'", type);
+      return FALSE;
+    }
+
+  if (!_dbus_marshal_basic_type (dest, type, data, endian))
+    {
+      _dbus_verbose ("failed to marshal type '%c'", type);
+      return FALSE;
+    }
+
+  if (*unalign)
+    {
+      _dbus_string_delete (dest, align_pad_start,
+                           align_pad_end - align_pad_start);
+      *unalign = FALSE;
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+parse_basic_array (DBusString *src, char type,
+                  DBusString *dest, dbus_bool_t *unalign,
+                  int endian)
+{
+  int array_align, elem_size;
+  int i, len, allocated;
+  unsigned char *values, b;
+  int values_offset;
+  int align_pad_start, align_pad_end;
+  dbus_bool_t retval = FALSE;
+
+  array_align = 4; /* length */
+  switch (type)
+    {
+    case DBUS_TYPE_BYTE:
+      elem_size = 1;
+      break;
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT32:
+      elem_size = 4;
+      break;
+    case DBUS_TYPE_DOUBLE:
+      array_align = 8;
+      elem_size = 8;
+      break;
+    default:
+      _dbus_assert_not_reached ("not a basic type");
+      break;
+    }
+
+  align_pad_start = _dbus_string_get_length (dest);
+  align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, array_align);
+
+  len = 0;
+  allocated = 2;
+  values = NULL;
+  values_offset = 0;
+         
+  _dbus_string_delete_first_word (src);
+  _dbus_string_skip_blank (src, 0, &i);
+  b = _dbus_string_get_byte (src, i++);
+
+  if (b != '{')
+    goto failed;
+
+  while (i < _dbus_string_get_length (src))
+    {
+      _dbus_string_skip_blank (src, i, &i);
+
+      if (!values || len == allocated - 1)
+       {
+         allocated *= 2;
+         values = dbus_realloc (values, allocated * elem_size);
+         if (!values)
+           {
+             _dbus_warn ("could not allocate memory for '%c' ARRAY\n", type);
+             goto failed;
+           }
+       }
+
+      if (!_dbus_string_parse_basic_type (src, type, i, values + values_offset, &i))
+       {
+         _dbus_warn ("could not parse integer element %d of '%c' ARRAY\n", len, type);
+         goto failed;
+       }
+
+      values_offset += elem_size;
+      len++;
+             
+      _dbus_string_skip_blank (src, i, &i);
+
+      b = _dbus_string_get_byte (src, i++);
+
+      if (b == '}')
+       break;
+      else if (b != ',')
+       goto failed;
+    }
+
+  if (!_dbus_marshal_basic_type_array (dest, type, values, len, endian))
+    {
+      _dbus_warn ("failed to append '%c' ARRAY\n", type);
+      goto failed;
+    }
+
+  if (*unalign)
+    {
+      _dbus_string_delete (dest, align_pad_start,
+                           align_pad_end - align_pad_start);
+      *unalign = FALSE;
+    }
+
+  retval = TRUE;
+
+ failed:
+  dbus_free (values);
+  return retval;
+}
+
+static char
+lookup_basic_type (const DBusString *str, dbus_bool_t *is_array)
+{
+  int i;
+  char type = DBUS_TYPE_INVALID;
+  static struct {
+    const char *name;
+    char        type;
+  } name_to_type[] = {
+    { "BYTE",    DBUS_TYPE_BYTE },
+    { "BOOLEAN", DBUS_TYPE_BOOLEAN },
+    { "INT32",   DBUS_TYPE_INT32 },
+    { "UINT32",  DBUS_TYPE_UINT32 },
+    { "DOUBLE",  DBUS_TYPE_DOUBLE }
+  };
+
+  for (i = 0; i < _DBUS_N_ELEMENTS(name_to_type); i++)
+    {
+      const char *name = name_to_type[i].name;
+      if (_dbus_string_starts_with_c_str (str, name)) 
+       {
+         int offset = strlen (name);
+         type = name_to_type[i].type;
+         if (is_array)
+           *is_array = _dbus_string_find (str, offset, "_ARRAY", NULL);
+         break;
+       }
+    }
+
+  return type;
+}
+
 /**
  * Reads the given filename, which should be in "message description
  * language" (look at some examples), and builds up the message data
@@ -274,7 +640,8 @@ append_saved_length (DBusString       *dest,
  * 
  * The file format is:
  * @code
- *   VALID_HEADER normal header; byte order, padding, header len, body len, serial
+ *   VALID_HEADER <type> normal header; byte order, type, padding, header len, body len, serial
+ *   REQUIRED_FIELDS add required fields with placeholder values
  *   BIG_ENDIAN switch to big endian
  *   LITTLE_ENDIAN switch to little endian
  *   OPPOSITE_ENDIAN switch to opposite endian
@@ -286,7 +653,7 @@ append_saved_length (DBusString       *dest,
  *                     (or if no START_LENGTH, absolute length)
  *   LENGTH <name> inserts the saved length of the same name
  *   CHOP <N> chops last N bytes off the data
- *   FIELD_NAME <abcd> inserts 4-byte field name
+ *   HEADER_FIELD <fieldname> inserts a header field name byte
  *   TYPE <typename> inserts a typecode byte 
  * @endcode
  * 
@@ -295,11 +662,17 @@ append_saved_length (DBusString       *dest,
  * @code
  *   INT32 <N> marshals an INT32
  *   UINT32 <N> marshals a UINT32
+ *   INT64 <N> marshals an INT64
+ *   UINT64 <N> marshals a UINT64
  *   DOUBLE <N> marshals a double
  *   STRING 'Foo' marshals a string
+ *   OBJECT_PATH '/foo/bar' marshals an object path
+ *   BYTE_ARRAY { 'a', 3, 4, 5, 6} marshals a BYTE array
+ *   BOOLEAN_ARRAY { false, true, false} marshals a BOOLEAN array
  *   INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array
  *   UINT32_ARRAY { 3, 4, 5, 6} marshals an UINT32 array
  *   DOUBLE_ARRAY { 1.0, 2.0, 3.0, 4.0} marshals a DOUBLE array  
+ *   STRING_ARRAY { "foo", "bar", "gazonk"} marshals a STRING array  
  * @endcode
  *
  * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
@@ -314,7 +687,7 @@ _dbus_message_data_load (DBusString       *dest,
                          const DBusString *filename)
 {
   DBusString file;
-  DBusResultCode result;
+  DBusError error;
   DBusString line;
   dbus_bool_t retval;
   int line_no;
@@ -322,26 +695,29 @@ _dbus_message_data_load (DBusString       *dest,
   DBusHashTable *length_hash;
   int endian;
   DBusHashIter iter;
+  char type;
+  dbus_bool_t is_array;
   
   retval = FALSE;
   length_hash = NULL;
   
-  if (!_dbus_string_init (&file, _DBUS_INT_MAX))
+  if (!_dbus_string_init (&file))
     return FALSE;
 
-  if (!_dbus_string_init (&line, _DBUS_INT_MAX))
+  if (!_dbus_string_init (&line))
     {
       _dbus_string_free (&file);
       return FALSE;
     }
-  
-  if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
+
+  _dbus_verbose ("Loading %s\n", _dbus_string_get_const_data (filename));
+
+  dbus_error_init (&error);
+  if (!_dbus_file_get_contents (&file, filename, &error))
     {
-      const char *s;
-      _dbus_string_get_const_data (filename, &s);
       _dbus_warn ("Getting contents of %s failed: %s\n",
-                  s, dbus_result_to_string (result));
-                     
+                  _dbus_string_get_const_data (filename), error.message);
+      dbus_error_free (&error);
       goto out;
     }
 
@@ -380,6 +756,13 @@ _dbus_message_data_load (DBusString       *dest,
         {
           int i;
           DBusString name;
+          int message_type;
+
+          if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
+            {
+              _dbus_warn ("no args to VALID_HEADER\n");
+              goto parse_failed;
+            }
           
           if (!_dbus_string_append_byte (dest, endian))
             {
@@ -387,8 +770,22 @@ _dbus_message_data_load (DBusString       *dest,
               goto parse_failed;
             }
 
+          message_type = message_type_from_string (&line,
+                                                   strlen ("VALID_HEADER "));
+          if (message_type < 0)
+            {
+              _dbus_warn ("VALID_HEADER not followed by space then known message type\n");
+              goto parse_failed;
+            }
+          
+          if (!_dbus_string_append_byte (dest, message_type))
+            {
+              _dbus_warn ("could not append message type\n");
+              goto parse_failed;
+            }
+          
           i = 0;
-          while (i < 3)
+          while (i < 2)
             {
               if (!_dbus_string_append_byte (dest, '\0'))
                 {
@@ -411,13 +808,41 @@ _dbus_message_data_load (DBusString       *dest,
             goto parse_failed;
           
           /* client serial */
-          if (!_dbus_marshal_int32 (dest, endian, 1))
+          if (!_dbus_marshal_uint32 (dest, endian, 1))
             {
               _dbus_warn ("couldn't append client serial\n");
               goto parse_failed;
             }
         }
       else if (_dbus_string_starts_with_c_str (&line,
+                                               "REQUIRED_FIELDS"))
+        {
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_INTERFACE,
+                                    DBUS_TYPE_STRING,
+                                    "org.freedesktop.BlahBlahInterface"))
+            goto parse_failed;
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_MEMBER,
+                                    DBUS_TYPE_STRING,
+                                    "BlahBlahMethod"))
+            goto parse_failed;
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_PATH,
+                                    DBUS_TYPE_OBJECT_PATH,
+                                    "/blah/blah/path"))
+            goto parse_failed;
+
+          /* FIXME later we'll validate this, and then it will break
+           * and the .message files will have to include the right thing
+           */
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_SIGNATURE,
+                                    DBUS_TYPE_STRING,
+                                    "iii"))
+            goto parse_failed;
+        }
+      else if (_dbus_string_starts_with_c_str (&line,
                                                "BIG_ENDIAN"))
         {
           endian = DBUS_BIG_ENDIAN;
@@ -439,24 +864,47 @@ _dbus_message_data_load (DBusString       *dest,
                                                "ALIGN"))
         {
           long val;
-
+          int end;
+          int orig_len;
+          
           _dbus_string_delete_first_word (&line);
 
-          if (!_dbus_string_parse_int (&line, 0, &val, NULL))
+          if (!_dbus_string_parse_int (&line, 0, &val, &end))
             {
               _dbus_warn ("Failed to parse integer\n");
               goto parse_failed;
             }
 
-          if (val > 16)
+          if (val > 8)
             {
               _dbus_warn ("Aligning to %ld boundary is crack\n",
                           val);
               goto parse_failed;
             }
+
+          orig_len = _dbus_string_get_length (dest);
           
           if (!_dbus_string_align_length (dest, val))
             goto parse_failed;
+
+          if (_dbus_string_parse_int (&line, end, &val, NULL))
+            {
+              /* If there's an optional second int argument,
+               * fill in align padding with that value
+               */
+              if (val < 0 || val > 255)
+                {
+                  _dbus_warn ("can't fill align padding with %ld, must be a byte value\n", val);
+                  goto parse_failed;
+                }
+
+              end = orig_len;
+              while (end < _dbus_string_get_length (dest))
+                {
+                  _dbus_string_set_byte (dest, end, val);
+                  ++end;
+                }
+            }
         }
       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
         {
@@ -489,38 +937,6 @@ _dbus_message_data_load (DBusString       *dest,
           
           _dbus_string_shorten (dest, val);
         }
-      else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
-        {
-          unsigned char the_byte;
-          
-          _dbus_string_delete_first_word (&line);
-
-          if (_dbus_string_equal_c_str (&line, "'\\''"))
-            the_byte = '\'';
-          else if (_dbus_string_get_byte (&line, 0) == '\'' &&
-                   _dbus_string_get_length (&line) >= 3 &&
-                   _dbus_string_get_byte (&line, 2) == '\'')
-            the_byte = _dbus_string_get_byte (&line, 1);
-          else
-            {
-              long val;
-              if (!_dbus_string_parse_int (&line, 0, &val, NULL))
-                {
-                  _dbus_warn ("Failed to parse integer for BYTE\n");
-                  goto parse_failed;
-                }
-
-              if (val > 255)
-                {
-                  _dbus_warn ("A byte must be in range 0-255 not %ld\n",
-                                 val);
-                  goto parse_failed;
-                }
-              the_byte = (unsigned char) val;
-            }
-
-          _dbus_string_append_byte (dest, the_byte);
-        }
       else if (_dbus_string_starts_with_c_str (&line,
                                                "START_LENGTH"))
         {
@@ -564,27 +980,44 @@ _dbus_message_data_load (DBusString       *dest,
           PERFORM_UNALIGN (dest);
         }
       else if (_dbus_string_starts_with_c_str (&line,
-                                               "FIELD_NAME"))
+                                               "HEADER_FIELD"))
         {
+         int field;
+
           _dbus_string_delete_first_word (&line);
 
-          if (_dbus_string_get_length (&line) != 4)
+          if (_dbus_string_starts_with_c_str (&line, "INVALID"))
+            field = DBUS_HEADER_FIELD_INVALID;
+          else if (_dbus_string_starts_with_c_str (&line, "PATH"))
+           field = DBUS_HEADER_FIELD_PATH;
+          else if (_dbus_string_starts_with_c_str (&line, "INTERFACE"))
+           field = DBUS_HEADER_FIELD_INTERFACE;
+          else if (_dbus_string_starts_with_c_str (&line, "MEMBER"))
+           field = DBUS_HEADER_FIELD_MEMBER;
+          else if (_dbus_string_starts_with_c_str (&line, "ERROR_NAME"))
+           field = DBUS_HEADER_FIELD_ERROR_NAME;
+          else if (_dbus_string_starts_with_c_str (&line, "REPLY_SERIAL"))
+           field = DBUS_HEADER_FIELD_REPLY_SERIAL;
+          else if (_dbus_string_starts_with_c_str (&line, "DESTINATION"))
+           field = DBUS_HEADER_FIELD_DESTINATION;
+          else if (_dbus_string_starts_with_c_str (&line, "SENDER"))
+           field = DBUS_HEADER_FIELD_SENDER;
+          else if (_dbus_string_starts_with_c_str (&line, "SIGNATURE"))
+           field = DBUS_HEADER_FIELD_SIGNATURE;
+         else if (_dbus_string_starts_with_c_str (&line, "UNKNOWN"))
+           field = 22; /* random unknown header field */
+          else
             {
-              const char *s;
-              _dbus_string_get_const_data (&line, &s);
-              _dbus_warn ("Field name must be four characters not \"%s\"\n",
-                             s);
+              _dbus_warn ("%s is not a valid header field name\n",
+                         _dbus_string_get_const_data (&line));
               goto parse_failed;
             }
 
-          if (unalign)
-            unalign = FALSE;
-          else
-            _dbus_string_align_length (dest, 4);
-          
-          if (!_dbus_string_copy (&line, 0, dest,
-                                  _dbus_string_get_length (dest)))
-            goto parse_failed;
+          if (!_dbus_string_append_byte (dest, field))
+           {
+              _dbus_warn ("could not append header field name byte\n");
+             goto parse_failed;
+           }
         }
       else if (_dbus_string_starts_with_c_str (&line,
                                                "TYPE"))
@@ -597,29 +1030,21 @@ _dbus_message_data_load (DBusString       *dest,
             code = DBUS_TYPE_INVALID;
           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
             code = DBUS_TYPE_NIL;
-          else if (_dbus_string_starts_with_c_str (&line, "INT32_ARRAY"))
-            code = DBUS_TYPE_INT32_ARRAY;
-          else if (_dbus_string_starts_with_c_str (&line, "UINT32_ARRAY"))
-            code = DBUS_TYPE_UINT32_ARRAY;
-          else if (_dbus_string_starts_with_c_str (&line, "DOUBLE_ARRAY"))
-            code = DBUS_TYPE_DOUBLE_ARRAY;
-          else if (_dbus_string_starts_with_c_str (&line, "BYTE_ARRAY"))
-            code = DBUS_TYPE_BYTE_ARRAY;
-          else if (_dbus_string_starts_with_c_str (&line, "STRING_ARRAY"))
-            code = DBUS_TYPE_STRING_ARRAY;
-          else if (_dbus_string_starts_with_c_str (&line, "INT32"))
-            code = DBUS_TYPE_INT32;
-          else if (_dbus_string_starts_with_c_str (&line, "UINT32"))
-            code = DBUS_TYPE_UINT32;
-          else if (_dbus_string_starts_with_c_str (&line, "DOUBLE"))
-            code = DBUS_TYPE_DOUBLE;
+         else if ((code = lookup_basic_type (&line, NULL)) != DBUS_TYPE_INVALID)
+           ;
           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
             code = DBUS_TYPE_STRING;
+          else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH"))
+            code = DBUS_TYPE_OBJECT_PATH;
+          else if (_dbus_string_starts_with_c_str (&line, "CUSTOM"))
+            code = DBUS_TYPE_CUSTOM;
+          else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
+            code = DBUS_TYPE_ARRAY;
+          else if (_dbus_string_starts_with_c_str (&line, "DICT"))
+            code = DBUS_TYPE_DICT;
           else
             {
-              const char *s;
-              _dbus_string_get_const_data (&line, &s);
-              _dbus_warn ("%s is not a valid type name\n", s);
+              _dbus_warn ("%s is not a valid type name\n", _dbus_string_get_const_data (&line));
               goto parse_failed;
             }
 
@@ -630,207 +1055,6 @@ _dbus_message_data_load (DBusString       *dest,
             }
         }
       else if (_dbus_string_starts_with_c_str (&line,
-                                              "INT32_ARRAY"))
-       {
-         SAVE_FOR_UNALIGN (dest, 4);
-         int i, len, allocated;
-         dbus_int32_t *values;
-         long val;
-         unsigned char b;
-
-         allocated = 4;
-         values = dbus_new (dbus_int32_t, allocated);
-         if (!values)
-           {
-             _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
-             goto parse_failed;
-           }
-         
-         len = 0;
-         
-         _dbus_string_delete_first_word (&line);
-         _dbus_string_skip_blank (&line, 0, &i);
-         b = _dbus_string_get_byte (&line, i++);
-
-         if (b != '{')
-           goto parse_failed;
-
-         while (i < _dbus_string_get_length (&line))
-           {
-             _dbus_string_skip_blank (&line, i, &i);
-
-             if (!_dbus_string_parse_int (&line, i, &val, &i))
-               {
-                 _dbus_warn ("could not parse integer for INT32_ARRAY\n");
-                 goto parse_failed;
-               }
-
-             values[len++] = val;
-             if (len == allocated)
-               {
-                 allocated *= 2;
-                 values = dbus_realloc (values, allocated * sizeof (dbus_int32_t));
-                 if (!values)
-                   {
-                     _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
-                     goto parse_failed;
-                   }
-               }
-             
-             _dbus_string_skip_blank (&line, i, &i);
-             
-             b = _dbus_string_get_byte (&line, i++);
-
-             if (b == '}')
-               break;
-             else if (b != ',')
-               goto parse_failed;
-           }
-
-          if (!_dbus_marshal_int32_array (dest, endian, values, len))
-            {
-              _dbus_warn ("failed to append INT32_ARRAY\n");
-              goto parse_failed;
-            }
-         dbus_free (values);
-         
-         PERFORM_UNALIGN (dest);
-       }
-      else if (_dbus_string_starts_with_c_str (&line,
-                                              "UINT32_ARRAY"))
-       {
-         SAVE_FOR_UNALIGN (dest, 4);
-         int i, len, allocated;
-         dbus_uint32_t *values;
-         long val;
-         unsigned char b;
-
-         allocated = 4;
-         values = dbus_new (dbus_uint32_t, allocated);
-         if (!values)
-           {
-             _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
-             goto parse_failed;
-           }
-         
-         len = 0;
-         
-         _dbus_string_delete_first_word (&line);
-         _dbus_string_skip_blank (&line, 0, &i);
-         b = _dbus_string_get_byte (&line, i++);
-
-         if (b != '{')
-           goto parse_failed;
-
-         while (i < _dbus_string_get_length (&line))
-           {
-             _dbus_string_skip_blank (&line, i, &i);
-
-             if (!_dbus_string_parse_int (&line, i, &val, &i))
-               {
-                 _dbus_warn ("could not parse integer for UINT32_ARRAY\n");
-                 goto parse_failed;
-               }
-
-             values[len++] = val;
-             if (len == allocated)
-               {
-                 allocated *= 2;
-                 values = dbus_realloc (values, allocated * sizeof (dbus_uint32_t));
-                 if (!values)
-                   {
-                     _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
-                     goto parse_failed;
-                   }
-               }
-             
-             _dbus_string_skip_blank (&line, i, &i);
-             
-             b = _dbus_string_get_byte (&line, i++);
-
-             if (b == '}')
-               break;
-             else if (b != ',')
-               goto parse_failed;
-           }
-
-          if (!_dbus_marshal_uint32_array (dest, endian, values, len))
-            {
-              _dbus_warn ("failed to append UINT32_ARRAY\n");
-              goto parse_failed;
-            }
-         dbus_free (values);
-         
-         PERFORM_UNALIGN (dest);
-       }
-      else if (_dbus_string_starts_with_c_str (&line,
-                                              "DOUBLE_ARRAY"))
-       {
-         SAVE_FOR_UNALIGN (dest, 8);
-         int i, len, allocated;
-         double *values;
-         double val;
-         unsigned char b;
-
-         allocated = 4;
-         values = dbus_new (double, allocated);
-         if (!values)
-           {
-             _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
-             goto parse_failed;
-           }
-         
-         len = 0;
-         
-         _dbus_string_delete_first_word (&line);
-         _dbus_string_skip_blank (&line, 0, &i);
-         b = _dbus_string_get_byte (&line, i++);
-
-         if (b != '{')
-           goto parse_failed;
-
-         while (i < _dbus_string_get_length (&line))
-           {
-             _dbus_string_skip_blank (&line, i, &i);
-
-             if (!_dbus_string_parse_double (&line, i, &val, &i))
-               {
-                 _dbus_warn ("could not parse double for DOUBLE_ARRAY\n");
-                 goto parse_failed;
-               }
-
-             values[len++] = val;
-             if (len == allocated)
-               {
-                 allocated *= 2;
-                 values = dbus_realloc (values, allocated * sizeof (double));
-                 if (!values)
-                   {
-                     _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
-                     goto parse_failed;
-                   }
-               }
-             
-             _dbus_string_skip_blank (&line, i, &i);
-             
-             b = _dbus_string_get_byte (&line, i++);
-
-             if (b == '}')
-               break;
-             else if (b != ',')
-               goto parse_failed;
-           }
-
-          if (!_dbus_marshal_double_array (dest, endian, values, len))
-            {
-              _dbus_warn ("failed to append DOUBLE_ARRAY\n");
-              goto parse_failed;
-            }
-         dbus_free (values);
-         
-         PERFORM_UNALIGN (dest);
-       }
-      else if (_dbus_string_starts_with_c_str (&line,
                                               "STRING_ARRAY"))
        {
          SAVE_FOR_UNALIGN (dest, 4);
@@ -844,7 +1068,7 @@ _dbus_message_data_load (DBusString       *dest,
          values = dbus_new (char *, allocated);
          if (!values)
            {
-             _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
+             _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
              goto parse_failed;
            }
          
@@ -857,7 +1081,7 @@ _dbus_message_data_load (DBusString       *dest,
          if (b != '{')
            goto parse_failed;
 
-         _dbus_string_init (&val_str, _DBUS_INT_MAX);
+         _dbus_string_init (&val_str);
          while (i < _dbus_string_get_length (&line))
            {
              _dbus_string_skip_blank (&line, i, &i);
@@ -913,78 +1137,58 @@ _dbus_message_data_load (DBusString       *dest,
          PERFORM_UNALIGN (dest);
        }
       else if (_dbus_string_starts_with_c_str (&line,
-                                               "INT32"))
+                                               "STRING"))
         {
           SAVE_FOR_UNALIGN (dest, 4);
-          long val;
+          int size_offset;
+          int old_len;
           
           _dbus_string_delete_first_word (&line);
 
-          if (!_dbus_string_parse_int (&line, 0, &val, NULL))
-            {
-              _dbus_warn ("could not parse integer for INT32\n");
-              goto parse_failed;
-            }
-          
-          if (!_dbus_marshal_int32 (dest, endian,
-                                    val))
+          size_offset = _dbus_string_get_length (dest);
+          size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
+          if (!_dbus_marshal_uint32 (dest, endian, 0))
             {
-              _dbus_warn ("failed to append INT32\n");
+              _dbus_warn ("Failed to append string size\n");
               goto parse_failed;
             }
 
-          PERFORM_UNALIGN (dest);
-        }
-      else if (_dbus_string_starts_with_c_str (&line,
-                                               "UINT32"))
-        {
-          SAVE_FOR_UNALIGN (dest, 4);
-          long val;
-          
-          _dbus_string_delete_first_word (&line);
-
-          /* FIXME should have _dbus_string_parse_uint32 */
-          if (!_dbus_string_parse_int (&line, 0, &val, NULL))
-            goto parse_failed;
-          
-          if (!_dbus_marshal_uint32 (dest, endian,
-                                     val))
+          old_len = _dbus_string_get_length (dest);
+          if (!append_quoted_string (dest, &line, 0, NULL))
             {
-              _dbus_warn ("failed to append UINT32\n");
+              _dbus_warn ("Failed to append quoted string\n");
               goto parse_failed;
             }
 
-          PERFORM_UNALIGN (dest);
-        }
-      else if (_dbus_string_starts_with_c_str (&line,
-                                               "DOUBLE"))
-        {
-          SAVE_FOR_UNALIGN (dest, 8);
-          double val;
-          
-          _dbus_string_delete_first_word (&line);
-
-          if (!_dbus_string_parse_double (&line, 0, &val, NULL))
-            goto parse_failed;
+          _dbus_marshal_set_uint32 (dest, size_offset,
+                                    /* subtract 1 for nul */
+                                    _dbus_string_get_length (dest) - old_len - 1,
+                                    endian);
           
-          if (!_dbus_marshal_double (dest, endian,
-                                     val))
-            {
-              _dbus_warn ("failed to append DOUBLE\n");
-              goto parse_failed;
-            }
-
           PERFORM_UNALIGN (dest);
         }
+      else if ((type = lookup_basic_type (&line, &is_array)) != DBUS_TYPE_INVALID)
+       {
+         if (is_array)
+           {
+             if (!parse_basic_array (&line, type, dest, &unalign, endian))
+               goto parse_failed;
+           }
+         else
+           {
+             if (!parse_basic_type (&line, type, dest, &unalign, endian))
+               goto parse_failed;
+           }
+        }
       else if (_dbus_string_starts_with_c_str (&line,
-                                               "STRING"))
+                                              "OBJECT_PATH"))
         {
           SAVE_FOR_UNALIGN (dest, 4);
           int size_offset;
           int old_len;
           
           _dbus_string_delete_first_word (&line);
-
+          
           size_offset = _dbus_string_get_length (dest);
           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
           if (!_dbus_marshal_uint32 (dest, endian, 0))
@@ -1000,12 +1204,13 @@ _dbus_message_data_load (DBusString       *dest,
               goto parse_failed;
             }
 
-          _dbus_marshal_set_uint32 (dest, endian, size_offset,
+          _dbus_marshal_set_uint32 (dest, size_offset,
                                     /* subtract 1 for nul */
-                                    _dbus_string_get_length (dest) - old_len - 1);
+                                    _dbus_string_get_length (dest) - old_len - 1,
+                                    endian);
           
           PERFORM_UNALIGN (dest);
-        }
+        }      
       else
         goto parse_failed;
       
@@ -1019,10 +1224,8 @@ _dbus_message_data_load (DBusString       *dest,
       
     parse_failed:
       {
-        const char *s;
-        _dbus_string_get_const_data (&line, &s);
         _dbus_warn ("couldn't process line %d \"%s\"\n",
-                    line_no, s);
+                    line_no, _dbus_string_get_const_data (&line));
         goto out;
       }
     }
@@ -1033,7 +1236,7 @@ _dbus_message_data_load (DBusString       *dest,
       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
       const char *s;
 
-      _dbus_string_get_const_data (&sl->name, &s);
+      s = _dbus_string_get_const_data (&sl->name);
       
       if (sl->length < 0)
         {
@@ -1064,6 +1267,8 @@ _dbus_message_data_load (DBusString       *dest,
     }
   
   retval = TRUE;
+
+  _dbus_verbose_bytes_of_string (dest, 0, _dbus_string_get_length (dest));
   
  out:
   if (length_hash != NULL)