D-Bus  1.4.16
dbus-message-factory.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-message-factory.c Generator of valid and invalid message data for test suite
00003  *
00004  * Copyright (C) 2005 Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 #include <config.h>
00024 
00025 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00026 
00027 #ifdef DBUS_BUILD_TESTS
00028 #include "dbus-message-factory.h"
00029 #include "dbus-message-private.h"
00030 #include "dbus-test.h"
00031 #include <stdio.h>
00032 
00033 typedef enum
00034   {
00035     CHANGE_TYPE_ADJUST,
00036     CHANGE_TYPE_ABSOLUTE
00037   } ChangeType;
00038 
00039 #define BYTE_ORDER_OFFSET  0
00040 #define TYPE_OFFSET        1
00041 #define BODY_LENGTH_OFFSET 4
00042 #define FIELDS_ARRAY_LENGTH_OFFSET 12
00043 
00044 static void
00045 iter_recurse (DBusMessageDataIter *iter)
00046 {
00047   iter->depth += 1;
00048   _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING);
00049   _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
00050 }
00051 
00052 static int
00053 iter_get_sequence (DBusMessageDataIter *iter)
00054 {
00055   _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
00056   return iter->sequence_nos[iter->depth];
00057 }
00058 
00059 static void
00060 iter_set_sequence (DBusMessageDataIter *iter,
00061                    int                  sequence)
00062 {
00063   _dbus_assert (sequence >= 0);
00064   iter->sequence_nos[iter->depth] = sequence;
00065 }
00066 
00067 static void
00068 iter_unrecurse (DBusMessageDataIter *iter)
00069 {
00070   iter->depth -= 1;
00071   _dbus_assert (iter->depth >= 0);
00072 }
00073 
00074 static void
00075 iter_next (DBusMessageDataIter *iter)
00076 {
00077   iter->sequence_nos[iter->depth] += 1;
00078 }
00079 
00080 static dbus_bool_t
00081 iter_first_in_series (DBusMessageDataIter *iter)
00082 {
00083   int i;
00084 
00085   i = iter->depth;
00086   while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
00087     {
00088       if (iter->sequence_nos[i] != 0)
00089         return FALSE;
00090       ++i;
00091     }
00092   return TRUE;
00093 }
00094 
00095 typedef dbus_bool_t (* DBusInnerGeneratorFunc)   (DBusMessageDataIter *iter,
00096                                                   DBusMessage        **message_p);
00097 typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter,
00098                                                   DBusString          *data,
00099                                                   DBusValidity        *expected_validity);
00100 
00101 static void
00102 set_reply_serial (DBusMessage *message)
00103 {
00104   if (message == NULL)
00105     _dbus_assert_not_reached ("oom");
00106   if (!dbus_message_set_reply_serial (message, 100))
00107     _dbus_assert_not_reached ("oom");
00108 }
00109 
00110 static dbus_bool_t
00111 generate_trivial_inner (DBusMessageDataIter *iter,
00112                         DBusMessage        **message_p)
00113 {
00114   DBusMessage *message;
00115 
00116   switch (iter_get_sequence (iter))
00117     {
00118     case 0:
00119       message = dbus_message_new_method_call ("org.freedesktop.TextEditor",
00120                                               "/foo/bar",
00121                                               "org.freedesktop.DocumentFactory",
00122                                               "Create");
00123       break;
00124     case 1:
00125       message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
00126       set_reply_serial (message);
00127       break;
00128     case 2:
00129       message = dbus_message_new_signal ("/foo/bar",
00130                                          "org.freedesktop.DocumentFactory",
00131                                          "Created");
00132       break;
00133     case 3:
00134       message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
00135 
00136       if (!dbus_message_set_error_name (message,
00137                                         "org.freedesktop.TestErrorName"))
00138         _dbus_assert_not_reached ("oom");
00139       
00140       {
00141         DBusMessageIter iter;
00142         const char *v_STRING = "This is an error";
00143         
00144         dbus_message_iter_init_append (message, &iter);
00145         if (!dbus_message_iter_append_basic (&iter,
00146                                              DBUS_TYPE_STRING,
00147                                              &v_STRING))
00148           _dbus_assert_not_reached ("oom");
00149       }
00150       
00151       set_reply_serial (message);
00152       break;
00153     default:
00154       return FALSE;
00155     }
00156   
00157   if (message == NULL)
00158     _dbus_assert_not_reached ("oom");
00159 
00160   *message_p = message;
00161   
00162   return TRUE;
00163 }
00164 
00165 static dbus_bool_t
00166 generate_many_bodies_inner (DBusMessageDataIter *iter,
00167                             DBusMessage        **message_p)
00168 {
00169   DBusMessage *message;
00170   DBusString signature;
00171   DBusString body;
00172 
00173   /* Keeping this small makes things go faster */
00174   message = dbus_message_new_method_call ("o.z.F",
00175                                           "/",
00176                                           "o.z.B",
00177                                           "Nah");
00178   if (message == NULL)
00179     _dbus_assert_not_reached ("oom");
00180 
00181   set_reply_serial (message);
00182 
00183   if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
00184     _dbus_assert_not_reached ("oom");
00185   
00186   if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter),
00187                                                 message->byte_order,
00188                                                 &signature, &body))
00189     {
00190       const char *v_SIGNATURE;
00191 
00192       v_SIGNATURE = _dbus_string_get_const_data (&signature);
00193       if (!_dbus_header_set_field_basic (&message->header,
00194                                          DBUS_HEADER_FIELD_SIGNATURE,
00195                                          DBUS_TYPE_SIGNATURE,
00196                                          &v_SIGNATURE))
00197         _dbus_assert_not_reached ("oom");
00198 
00199       if (!_dbus_string_move (&body, 0, &message->body, 0))
00200         _dbus_assert_not_reached ("oom");
00201 
00202       _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET,
00203                                 _dbus_string_get_length (&message->body),
00204                                 message->byte_order);
00205       
00206       *message_p = message;
00207     }
00208   else
00209     {
00210       dbus_message_unref (message);
00211       *message_p = NULL;
00212     }
00213   
00214   _dbus_string_free (&signature);
00215   _dbus_string_free (&body);
00216 
00217   return *message_p != NULL;
00218 }
00219 
00220 static void
00221 generate_from_message (DBusString            *data,
00222                        DBusValidity          *expected_validity,
00223                        DBusMessage           *message)
00224 {
00225   dbus_message_set_serial (message, 1);
00226   dbus_message_lock (message);
00227 
00228   *expected_validity = DBUS_VALID;
00229   
00230   /* move for efficiency, since we'll nuke the message anyway */
00231   if (!_dbus_string_move (&message->header.data, 0,
00232                           data, 0))
00233     _dbus_assert_not_reached ("oom");
00234 
00235   if (!_dbus_string_copy (&message->body, 0,
00236                           data, _dbus_string_get_length (data)))
00237     _dbus_assert_not_reached ("oom");
00238 }
00239 
00240 static dbus_bool_t
00241 generate_outer (DBusMessageDataIter   *iter,
00242                 DBusString            *data,
00243                 DBusValidity          *expected_validity,
00244                 DBusInnerGeneratorFunc func)
00245 {
00246   DBusMessage *message;
00247 
00248   message = NULL;
00249   if (!(*func)(iter, &message))
00250     return FALSE;
00251 
00252   iter_next (iter);
00253   
00254   _dbus_assert (message != NULL);
00255 
00256   generate_from_message (data, expected_validity, message);
00257 
00258   dbus_message_unref (message);
00259 
00260   return TRUE;
00261 }
00262 
00263 static dbus_bool_t
00264 generate_trivial (DBusMessageDataIter   *iter,
00265                   DBusString            *data,
00266                   DBusValidity          *expected_validity)
00267 {
00268   return generate_outer (iter, data, expected_validity,
00269                          generate_trivial_inner);
00270 }
00271 
00272 static dbus_bool_t
00273 generate_many_bodies (DBusMessageDataIter   *iter,
00274                       DBusString            *data,
00275                       DBusValidity          *expected_validity)
00276 {
00277   return generate_outer (iter, data, expected_validity,
00278                          generate_many_bodies_inner);
00279 }
00280 
00281 static DBusMessage*
00282 simple_method_call (void)
00283 {
00284   DBusMessage *message;
00285   /* Keeping this small makes stuff go faster */
00286   message = dbus_message_new_method_call ("o.b.Q",
00287                                           "/f/b",
00288                                           "o.b.Z",
00289                                           "Fro");
00290   if (message == NULL)
00291     _dbus_assert_not_reached ("oom");
00292   return message;
00293 }
00294 
00295 static DBusMessage*
00296 simple_signal (void)
00297 {
00298   DBusMessage *message;
00299   message = dbus_message_new_signal ("/f/b",
00300                                      "o.b.Z",
00301                                      "Fro");
00302   if (message == NULL)
00303     _dbus_assert_not_reached ("oom");
00304   return message;
00305 }
00306 
00307 static DBusMessage*
00308 simple_method_return (void)
00309 {
00310   DBusMessage *message;
00311   message =  dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
00312   if (message == NULL)
00313     _dbus_assert_not_reached ("oom");
00314 
00315   set_reply_serial (message);
00316   
00317   return message;
00318 }
00319 
00320 static DBusMessage*
00321 simple_error (void)
00322 {
00323   DBusMessage *message;
00324   message =  dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
00325   if (message == NULL)
00326     _dbus_assert_not_reached ("oom");
00327 
00328   if (!dbus_message_set_error_name (message, "foo.bar"))
00329     _dbus_assert_not_reached ("oom");
00330   
00331   set_reply_serial (message);
00332   
00333   return message;
00334 }
00335 
00336 static DBusMessage*
00337 message_with_nesting_levels (int levels)
00338 {
00339   DBusMessage *message;
00340   dbus_int32_t v_INT32;
00341   DBusMessageIter *parents;
00342   DBusMessageIter *children;
00343   int i;
00344 
00345   /* If levels is higher it breaks sig_refcount in DBusMessageRealIter
00346    * in dbus-message.c, this assert is just to help you know you need
00347    * to fix that if you hit it
00348    */
00349   _dbus_assert (levels < 256);
00350 
00351   parents = dbus_new(DBusMessageIter, levels + 1);
00352   children = dbus_new(DBusMessageIter, levels + 1);
00353 
00354   v_INT32 = 42;
00355   message = simple_method_call ();
00356 
00357   i = 0;
00358   dbus_message_iter_init_append (message, &parents[i]);
00359   while (i < levels)
00360     {
00361       dbus_message_iter_open_container (&parents[i], DBUS_TYPE_VARIANT,
00362                                         i == (levels - 1) ?
00363                                         DBUS_TYPE_INT32_AS_STRING :
00364                                         DBUS_TYPE_VARIANT_AS_STRING,
00365                                         &children[i]);
00366       ++i;
00367       parents[i] = children[i-1];
00368     }
00369   --i;
00370   dbus_message_iter_append_basic (&children[i], DBUS_TYPE_INT32, &v_INT32);
00371   while (i >= 0)
00372     {
00373       dbus_message_iter_close_container (&parents[i], &children[i]);
00374       --i;
00375     }
00376 
00377   dbus_free(parents);
00378   dbus_free(children);
00379 
00380   return message;
00381 }
00382 
00383 static dbus_bool_t
00384 generate_special (DBusMessageDataIter   *iter,
00385                   DBusString            *data,
00386                   DBusValidity          *expected_validity)
00387 {
00388   int item_seq;
00389   DBusMessage *message;
00390   int pos;
00391   dbus_int32_t v_INT32;
00392 
00393   _dbus_assert (_dbus_string_get_length (data) == 0);
00394   
00395   message = NULL;
00396   pos = -1;
00397   v_INT32 = 42;
00398   item_seq = iter_get_sequence (iter);
00399 
00400   if (item_seq == 0)
00401     {
00402       message = simple_method_call ();
00403       if (!dbus_message_append_args (message,
00404                                      DBUS_TYPE_INT32, &v_INT32,
00405                                      DBUS_TYPE_INT32, &v_INT32,
00406                                      DBUS_TYPE_INT32, &v_INT32,
00407                                      DBUS_TYPE_INVALID))
00408         _dbus_assert_not_reached ("oom");
00409                                      
00410       _dbus_header_get_field_raw (&message->header,
00411                                   DBUS_HEADER_FIELD_SIGNATURE,
00412                                   NULL, &pos);
00413       generate_from_message (data, expected_validity, message);
00414       
00415       /* set an invalid typecode */
00416       _dbus_string_set_byte (data, pos + 1, '$');
00417 
00418       *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE;
00419     }
00420   else if (item_seq == 1)
00421     {
00422       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2];
00423       const char *v_STRING;
00424       int i;
00425       
00426       message = simple_method_call ();
00427       if (!dbus_message_append_args (message,
00428                                      DBUS_TYPE_INT32, &v_INT32,
00429                                      DBUS_TYPE_INT32, &v_INT32,
00430                                      DBUS_TYPE_INT32, &v_INT32,
00431                                      DBUS_TYPE_INVALID))
00432         _dbus_assert_not_reached ("oom");
00433 
00434       i = 0;
00435       while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
00436         {
00437           long_sig[i] = DBUS_TYPE_ARRAY;
00438           ++i;
00439         }
00440       long_sig[i] = DBUS_TYPE_INVALID;
00441 
00442       v_STRING = long_sig;
00443       if (!_dbus_header_set_field_basic (&message->header,
00444                                          DBUS_HEADER_FIELD_SIGNATURE,
00445                                          DBUS_TYPE_SIGNATURE,
00446                                          &v_STRING))
00447         _dbus_assert_not_reached ("oom");
00448       
00449       _dbus_header_get_field_raw (&message->header,
00450                                   DBUS_HEADER_FIELD_SIGNATURE,
00451                                   NULL, &pos);
00452       generate_from_message (data, expected_validity, message);
00453       
00454       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
00455     }
00456   else if (item_seq == 2)
00457     {
00458       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4];
00459       const char *v_STRING;
00460       int i;
00461       
00462       message = simple_method_call ();
00463       if (!dbus_message_append_args (message,
00464                                      DBUS_TYPE_INT32, &v_INT32,
00465                                      DBUS_TYPE_INT32, &v_INT32,
00466                                      DBUS_TYPE_INT32, &v_INT32,
00467                                      DBUS_TYPE_INVALID))
00468         _dbus_assert_not_reached ("oom");
00469 
00470       i = 0;
00471       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
00472         {
00473           long_sig[i] = DBUS_STRUCT_BEGIN_CHAR;
00474           ++i;
00475         }
00476 
00477       long_sig[i] = DBUS_TYPE_INT32;
00478       ++i;
00479 
00480       while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3))
00481         {
00482           long_sig[i] = DBUS_STRUCT_END_CHAR;
00483           ++i;
00484         }
00485       long_sig[i] = DBUS_TYPE_INVALID;
00486       
00487       v_STRING = long_sig;
00488       if (!_dbus_header_set_field_basic (&message->header,
00489                                          DBUS_HEADER_FIELD_SIGNATURE,
00490                                          DBUS_TYPE_SIGNATURE,
00491                                          &v_STRING))
00492         _dbus_assert_not_reached ("oom");
00493       
00494       _dbus_header_get_field_raw (&message->header,
00495                                   DBUS_HEADER_FIELD_SIGNATURE,
00496                                   NULL, &pos);
00497       generate_from_message (data, expected_validity, message);
00498       
00499       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
00500     }
00501   else if (item_seq == 3)
00502     {
00503       message = simple_method_call ();
00504       if (!dbus_message_append_args (message,
00505                                      DBUS_TYPE_INT32, &v_INT32,
00506                                      DBUS_TYPE_INT32, &v_INT32,
00507                                      DBUS_TYPE_INT32, &v_INT32,
00508                                      DBUS_TYPE_INVALID))
00509         _dbus_assert_not_reached ("oom");
00510                                      
00511       _dbus_header_get_field_raw (&message->header,
00512                                   DBUS_HEADER_FIELD_SIGNATURE,
00513                                   NULL, &pos);
00514       generate_from_message (data, expected_validity, message);
00515       
00516       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
00517       
00518       *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
00519     }
00520   else if (item_seq == 4)
00521     {
00522       message = simple_method_call ();
00523       if (!dbus_message_append_args (message,
00524                                      DBUS_TYPE_INT32, &v_INT32,
00525                                      DBUS_TYPE_INT32, &v_INT32,
00526                                      DBUS_TYPE_INT32, &v_INT32,
00527                                      DBUS_TYPE_INVALID))
00528         _dbus_assert_not_reached ("oom");
00529                                      
00530       _dbus_header_get_field_raw (&message->header,
00531                                   DBUS_HEADER_FIELD_SIGNATURE,
00532                                   NULL, &pos);
00533       generate_from_message (data, expected_validity, message);
00534       
00535       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR);
00536       
00537       *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
00538     }
00539   else if (item_seq == 5)
00540     {
00541       message = simple_method_call ();
00542       if (!dbus_message_append_args (message,
00543                                      DBUS_TYPE_INT32, &v_INT32,
00544                                      DBUS_TYPE_INT32, &v_INT32,
00545                                      DBUS_TYPE_INT32, &v_INT32,
00546                                      DBUS_TYPE_INVALID))
00547         _dbus_assert_not_reached ("oom");
00548                                      
00549       _dbus_header_get_field_raw (&message->header,
00550                                   DBUS_HEADER_FIELD_SIGNATURE,
00551                                   NULL, &pos);
00552       generate_from_message (data, expected_validity, message);
00553       
00554       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
00555       _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR);
00556       
00557       *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
00558     }
00559   else if (item_seq == 6)
00560     {
00561       message = simple_method_call ();
00562       generate_from_message (data, expected_validity, message);
00563       
00564       _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID);
00565       
00566       *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE;
00567     }
00568   else if (item_seq == 7)
00569     {
00570       /* Messages of unknown type are considered valid */
00571       message = simple_method_call ();
00572       generate_from_message (data, expected_validity, message);
00573       
00574       _dbus_string_set_byte (data, TYPE_OFFSET, 100);
00575       
00576       *expected_validity = DBUS_VALID;
00577     }
00578   else if (item_seq == 8)
00579     {
00580       message = simple_method_call ();
00581       generate_from_message (data, expected_validity, message);
00582       
00583       _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
00584                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
00585                                 message->byte_order);
00586       _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET,
00587                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
00588                                 message->byte_order);
00589       *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG;
00590     }
00591   else if (item_seq == 9)
00592     {
00593       const char *v_STRING = "not a valid bus name";
00594       message = simple_method_call ();
00595 
00596       if (!_dbus_header_set_field_basic (&message->header,
00597                                          DBUS_HEADER_FIELD_SENDER,
00598                                          DBUS_TYPE_STRING, &v_STRING))
00599         _dbus_assert_not_reached ("oom");
00600       
00601       generate_from_message (data, expected_validity, message);
00602 
00603       *expected_validity = DBUS_INVALID_BAD_SENDER;
00604     }
00605   else if (item_seq == 10)
00606     {
00607       message = simple_method_call ();
00608 
00609       if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL))
00610         _dbus_assert_not_reached ("oom");
00611       
00612       generate_from_message (data, expected_validity, message);
00613 
00614       *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE;
00615     }
00616   else if (item_seq == 11)
00617     {
00618       message = simple_method_call ();
00619 
00620       if (!dbus_message_set_path (message, DBUS_PATH_LOCAL))
00621         _dbus_assert_not_reached ("oom");
00622       
00623       generate_from_message (data, expected_validity, message);
00624 
00625       *expected_validity = DBUS_INVALID_USES_LOCAL_PATH;
00626     }
00627   else if (item_seq == 12)
00628     {
00629       /* Method calls don't have to have interface */
00630       message = simple_method_call ();
00631 
00632       if (!dbus_message_set_interface (message, NULL))
00633         _dbus_assert_not_reached ("oom");
00634       
00635       generate_from_message (data, expected_validity, message);
00636       
00637       *expected_validity = DBUS_VALID;
00638     }
00639   else if (item_seq == 13)
00640     {
00641       /* Signals require an interface */
00642       message = simple_signal ();
00643 
00644       if (!dbus_message_set_interface (message, NULL))
00645         _dbus_assert_not_reached ("oom");
00646       
00647       generate_from_message (data, expected_validity, message);
00648       
00649       *expected_validity = DBUS_INVALID_MISSING_INTERFACE;
00650     }
00651   else if (item_seq == 14)
00652     {
00653       message = simple_method_return ();
00654 
00655       if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL))
00656         _dbus_assert_not_reached ("oom");
00657       
00658       generate_from_message (data, expected_validity, message);
00659       
00660       *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL;
00661     }
00662   else if (item_seq == 15)
00663     {
00664       message = simple_error ();
00665 
00666       if (!dbus_message_set_error_name (message, NULL))
00667         _dbus_assert_not_reached ("oom");
00668       
00669       generate_from_message (data, expected_validity, message);
00670       
00671       *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME;
00672     }
00673   else if (item_seq == 16)
00674     {
00675       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+10];
00676       const char *v_STRING;
00677       int i;
00678       int n_begins;
00679       
00680       message = simple_method_call ();
00681       if (!dbus_message_append_args (message,
00682                                      DBUS_TYPE_INT32, &v_INT32,
00683                                      DBUS_TYPE_INT32, &v_INT32,
00684                                      DBUS_TYPE_INT32, &v_INT32,
00685                                      DBUS_TYPE_INVALID))
00686         _dbus_assert_not_reached ("oom");
00687 
00688       i = 0;
00689       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3))
00690         {
00691           long_sig[i] = DBUS_TYPE_ARRAY;
00692           ++i;
00693           long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR;
00694           ++i;
00695           long_sig[i] = DBUS_TYPE_INT32;
00696           ++i;
00697         }
00698       n_begins = i / 3;
00699 
00700       long_sig[i] = DBUS_TYPE_INT32;
00701       ++i;
00702       
00703       while (n_begins > 0)
00704         {
00705           long_sig[i] = DBUS_DICT_ENTRY_END_CHAR;
00706           ++i;
00707           n_begins -= 1;
00708         }
00709       long_sig[i] = DBUS_TYPE_INVALID;
00710       
00711       v_STRING = long_sig;
00712       if (!_dbus_header_set_field_basic (&message->header,
00713                                          DBUS_HEADER_FIELD_SIGNATURE,
00714                                          DBUS_TYPE_SIGNATURE,
00715                                          &v_STRING))
00716         _dbus_assert_not_reached ("oom");
00717       
00718       _dbus_header_get_field_raw (&message->header,
00719                                   DBUS_HEADER_FIELD_SIGNATURE,
00720                                   NULL, &pos);
00721       generate_from_message (data, expected_validity, message);
00722       
00723       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
00724     }
00725   else if (item_seq == 17)
00726     {
00727       message = simple_method_call ();
00728       if (!dbus_message_append_args (message,
00729                                      DBUS_TYPE_INT32, &v_INT32,
00730                                      DBUS_TYPE_INT32, &v_INT32,
00731                                      DBUS_TYPE_INT32, &v_INT32,
00732                                      DBUS_TYPE_INVALID))
00733         _dbus_assert_not_reached ("oom");
00734                                      
00735       _dbus_header_get_field_raw (&message->header,
00736                                   DBUS_HEADER_FIELD_SIGNATURE,
00737                                   NULL, &pos);
00738       generate_from_message (data, expected_validity, message);
00739 
00740       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
00741       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
00742       
00743       *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
00744     }
00745   else if (item_seq == 18)
00746     {
00747       message = simple_method_call ();
00748       if (!dbus_message_append_args (message,
00749                                      DBUS_TYPE_INT32, &v_INT32,
00750                                      DBUS_TYPE_INT32, &v_INT32,
00751                                      DBUS_TYPE_INT32, &v_INT32,
00752                                      DBUS_TYPE_INVALID))
00753         _dbus_assert_not_reached ("oom");
00754                                      
00755       _dbus_header_get_field_raw (&message->header,
00756                                   DBUS_HEADER_FIELD_SIGNATURE,
00757                                   NULL, &pos);
00758       generate_from_message (data, expected_validity, message);
00759       
00760       _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR);
00761       
00762       *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
00763     }
00764   else if (item_seq == 19)
00765     {
00766       message = simple_method_call ();
00767       if (!dbus_message_append_args (message,
00768                                      DBUS_TYPE_INT32, &v_INT32,
00769                                      DBUS_TYPE_INT32, &v_INT32,
00770                                      DBUS_TYPE_INT32, &v_INT32,
00771                                      DBUS_TYPE_INVALID))
00772         _dbus_assert_not_reached ("oom");
00773                                      
00774       _dbus_header_get_field_raw (&message->header,
00775                                   DBUS_HEADER_FIELD_SIGNATURE,
00776                                   NULL, &pos);
00777       generate_from_message (data, expected_validity, message);
00778 
00779       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
00780       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
00781       _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR);
00782       
00783       *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
00784     }
00785   else if (item_seq == 20)
00786     {
00787       /* 64 levels of nesting is OK */
00788       message = message_with_nesting_levels(64);
00789 
00790       generate_from_message (data, expected_validity, message);
00791 
00792       *expected_validity = DBUS_VALID;
00793     }
00794   else if (item_seq == 21)
00795     {
00796       /* 65 levels of nesting is not OK */
00797       message = message_with_nesting_levels(65);
00798 
00799       generate_from_message (data, expected_validity, message);
00800 
00801       *expected_validity = DBUS_INVALID_NESTED_TOO_DEEPLY;
00802     }
00803   else
00804     {
00805       return FALSE;
00806     }
00807 
00808   if (message)
00809     dbus_message_unref (message);
00810 
00811   iter_next (iter);
00812   return TRUE;
00813 }
00814 
00815 static dbus_bool_t
00816 generate_wrong_length (DBusMessageDataIter *iter,
00817                        DBusString          *data,
00818                        DBusValidity        *expected_validity)
00819 {
00820   int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1,
00821                     1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 };
00822   int adjust;
00823   int len_seq;
00824 
00825  restart:
00826   len_seq = iter_get_sequence (iter);
00827   if (len_seq == _DBUS_N_ELEMENTS (lengths))
00828     return FALSE;
00829 
00830   _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths));
00831   
00832   iter_recurse (iter);
00833   if (!generate_many_bodies (iter, data, expected_validity))
00834     {
00835       iter_set_sequence (iter, 0); /* reset to first body */
00836       iter_unrecurse (iter);
00837       iter_next (iter);            /* next length adjustment */
00838       goto restart;
00839     }
00840   iter_unrecurse (iter);
00841 
00842   adjust = lengths[len_seq];
00843 
00844   if (adjust < 0)
00845     {
00846       if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE)
00847         _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE);
00848       else
00849         _dbus_string_shorten (data, - adjust);
00850       *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON;
00851     }
00852   else
00853     {      
00854       if (!_dbus_string_lengthen (data, adjust))
00855         _dbus_assert_not_reached ("oom");
00856       *expected_validity = DBUS_INVALID_TOO_MUCH_DATA;
00857     }
00858 
00859   /* Fixup lengths */
00860   {
00861     int old_body_len;
00862     int new_body_len;
00863     int byte_order;
00864     
00865     _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE);
00866     
00867     byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
00868     old_body_len = _dbus_marshal_read_uint32 (data,
00869                                               BODY_LENGTH_OFFSET,
00870                                               byte_order,
00871                                               NULL);
00872     _dbus_assert (old_body_len < _dbus_string_get_length (data));
00873     new_body_len = old_body_len + adjust;
00874     if (new_body_len < 0)
00875       {
00876         new_body_len = 0;
00877         /* we just munged the header, and aren't sure how */
00878         *expected_validity = DBUS_VALIDITY_UNKNOWN;
00879       }
00880 
00881     _dbus_verbose ("changing body len from %u to %u by adjust %d\n",
00882                    old_body_len, new_body_len, adjust);
00883     
00884     _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
00885                               new_body_len,
00886                               byte_order);
00887   }
00888 
00889   return TRUE;
00890 }
00891 
00892 static dbus_bool_t
00893 generate_byte_changed (DBusMessageDataIter *iter,
00894                        DBusString          *data,
00895                        DBusValidity        *expected_validity)
00896 {
00897   int byte_seq;
00898   int v_BYTE;
00899 
00900   /* This is a little convoluted to make the bodies the
00901    * outer loop and each byte of each body the inner
00902    * loop
00903    */
00904 
00905  restart:
00906   if (!generate_many_bodies (iter, data, expected_validity))
00907     return FALSE;
00908 
00909   iter_recurse (iter);
00910   byte_seq = iter_get_sequence (iter);
00911   iter_next (iter);
00912   iter_unrecurse (iter);
00913   
00914   if (byte_seq == _dbus_string_get_length (data))
00915     {
00916       _dbus_string_set_length (data, 0);
00917       /* reset byte count */
00918       iter_recurse (iter);
00919       iter_set_sequence (iter, 0);
00920       iter_unrecurse (iter);
00921       goto restart;
00922     }
00923   else
00924     {
00925       /* Undo the "next" in generate_many_bodies */
00926       iter_set_sequence (iter, iter_get_sequence (iter) - 1);
00927     }
00928 
00929   _dbus_assert (byte_seq < _dbus_string_get_length (data));
00930   v_BYTE = _dbus_string_get_byte (data, byte_seq);
00931   v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */
00932   _dbus_string_set_byte (data, byte_seq, v_BYTE);
00933   *expected_validity = DBUS_VALIDITY_UNKNOWN;
00934 
00935   return TRUE;
00936 }
00937 
00938 static dbus_bool_t
00939 find_next_typecode (DBusMessageDataIter *iter,
00940                     DBusString          *data,
00941                     DBusValidity        *expected_validity)
00942 {
00943   int body_seq;
00944   int byte_seq;
00945   int base_depth;
00946 
00947   base_depth = iter->depth;
00948 
00949  restart:
00950   _dbus_assert (iter->depth == (base_depth + 0));
00951   _dbus_string_set_length (data, 0);
00952 
00953   body_seq = iter_get_sequence (iter);
00954   
00955   if (!generate_many_bodies (iter, data, expected_validity))
00956     return FALSE;
00957   /* Undo the "next" in generate_many_bodies */
00958   iter_set_sequence (iter, body_seq);
00959   
00960   iter_recurse (iter);
00961   while (TRUE)
00962     {
00963       _dbus_assert (iter->depth == (base_depth + 1));
00964       
00965       byte_seq = iter_get_sequence (iter);
00966 
00967       _dbus_assert (byte_seq <= _dbus_string_get_length (data));
00968       
00969       if (byte_seq == _dbus_string_get_length (data))
00970         {
00971           /* reset byte count */
00972           iter_set_sequence (iter, 0);
00973           iter_unrecurse (iter);
00974           _dbus_assert (iter->depth == (base_depth + 0));
00975           iter_next (iter); /* go to the next body */
00976           goto restart;
00977         }
00978 
00979       _dbus_assert (byte_seq < _dbus_string_get_length (data));
00980 
00981       if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
00982         break;
00983       else
00984         iter_next (iter);
00985     }
00986 
00987   _dbus_assert (byte_seq == iter_get_sequence (iter));
00988   _dbus_assert (byte_seq < _dbus_string_get_length (data));
00989 
00990   iter_unrecurse (iter);
00991 
00992   _dbus_assert (iter->depth == (base_depth + 0));
00993   
00994   return TRUE;
00995 }
00996 
00997 static const int typecodes[] = {
00998   DBUS_TYPE_INVALID,
00999   DBUS_TYPE_BYTE,
01000   DBUS_TYPE_BOOLEAN,
01001   DBUS_TYPE_INT16,
01002   DBUS_TYPE_UINT16,
01003   DBUS_TYPE_INT32,
01004   DBUS_TYPE_UINT32,
01005   DBUS_TYPE_INT64,
01006   DBUS_TYPE_UINT64,
01007   DBUS_TYPE_DOUBLE,
01008   DBUS_TYPE_STRING,
01009   DBUS_TYPE_OBJECT_PATH,
01010   DBUS_TYPE_SIGNATURE,
01011   DBUS_TYPE_ARRAY,
01012   DBUS_TYPE_VARIANT,
01013   DBUS_STRUCT_BEGIN_CHAR,
01014   DBUS_STRUCT_END_CHAR,
01015   DBUS_DICT_ENTRY_BEGIN_CHAR,
01016   DBUS_DICT_ENTRY_END_CHAR,
01017   DBUS_TYPE_UNIX_FD,
01018   255 /* random invalid typecode */
01019 };
01020   
01021 static dbus_bool_t
01022 generate_typecode_changed (DBusMessageDataIter *iter,
01023                            DBusString          *data,
01024                            DBusValidity        *expected_validity)
01025 {
01026   int byte_seq;
01027   int typecode_seq;
01028   int base_depth;
01029 
01030   base_depth = iter->depth;
01031 
01032  restart:
01033   _dbus_assert (iter->depth == (base_depth + 0));
01034   _dbus_string_set_length (data, 0);
01035   
01036   if (!find_next_typecode (iter, data, expected_validity))
01037     return FALSE;
01038 
01039   iter_recurse (iter);
01040   byte_seq = iter_get_sequence (iter);
01041 
01042   _dbus_assert (byte_seq < _dbus_string_get_length (data));
01043   
01044   iter_recurse (iter);
01045   typecode_seq = iter_get_sequence (iter);
01046   iter_next (iter);
01047 
01048   _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes));
01049   
01050   if (typecode_seq == _DBUS_N_ELEMENTS (typecodes))
01051     {
01052       _dbus_assert (iter->depth == (base_depth + 2));
01053       iter_set_sequence (iter, 0); /* reset typecode sequence */
01054       iter_unrecurse (iter);
01055       _dbus_assert (iter->depth == (base_depth + 1));
01056       iter_next (iter); /* go to the next byte_seq */
01057       iter_unrecurse (iter);
01058       _dbus_assert (iter->depth == (base_depth + 0));
01059       goto restart;
01060     }
01061 
01062   _dbus_assert (iter->depth == (base_depth + 2));
01063   iter_unrecurse (iter);
01064   _dbus_assert (iter->depth == (base_depth + 1));
01065   iter_unrecurse (iter);
01066   _dbus_assert (iter->depth == (base_depth + 0));
01067 
01068 #if 0
01069   printf ("Changing byte %d in message %d to %c\n",
01070           byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]);
01071 #endif
01072   
01073   _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]);
01074   *expected_validity = DBUS_VALIDITY_UNKNOWN;
01075   return TRUE;
01076 }
01077 
01078 typedef struct
01079 {
01080   ChangeType type;
01081   dbus_uint32_t value; /* cast to signed for adjusts */
01082 } UIntChange;
01083 
01084 static const UIntChange uint32_changes[] = {
01085   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 },
01086   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 },
01087   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 },
01088   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 },
01089   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 },
01090   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 },
01091   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX },
01092   { CHANGE_TYPE_ABSOLUTE, 0 },
01093   { CHANGE_TYPE_ABSOLUTE, 1 },
01094   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 },
01095   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 }
01096 };
01097 
01098 static dbus_bool_t
01099 generate_uint32_changed (DBusMessageDataIter *iter,
01100                          DBusString          *data,
01101                          DBusValidity        *expected_validity)
01102 {
01103   int body_seq;
01104   int byte_seq;
01105   int change_seq;
01106   dbus_uint32_t v_UINT32;
01107   int byte_order;
01108   const UIntChange *change;
01109   int base_depth;
01110 
01111   /* Outer loop is each body, next loop is each change,
01112    * inner loop is each change location
01113    */
01114 
01115   base_depth = iter->depth;
01116   
01117  next_body:
01118   _dbus_assert (iter->depth == (base_depth + 0));
01119   _dbus_string_set_length (data, 0);
01120   body_seq = iter_get_sequence (iter);
01121   
01122   if (!generate_many_bodies (iter, data, expected_validity))
01123     return FALSE;
01124 
01125   _dbus_assert (iter->depth == (base_depth + 0));
01126 
01127   iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */
01128   iter_recurse (iter);
01129  next_change:
01130   _dbus_assert (iter->depth == (base_depth + 1));
01131   change_seq = iter_get_sequence (iter);
01132   
01133   if (change_seq == _DBUS_N_ELEMENTS (uint32_changes))
01134     {
01135       /* Reset change count */
01136       iter_set_sequence (iter, 0);
01137       iter_unrecurse (iter);
01138       iter_next (iter);
01139       goto next_body;
01140     }
01141 
01142   _dbus_assert (iter->depth == (base_depth + 1));
01143   
01144   iter_recurse (iter);
01145   _dbus_assert (iter->depth == (base_depth + 2));
01146   byte_seq = iter_get_sequence (iter);
01147   /* skip 4 bytes at a time */
01148   iter_next (iter);
01149   iter_next (iter);
01150   iter_next (iter);
01151   iter_next (iter);
01152   iter_unrecurse (iter);
01153 
01154   _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq);
01155   if (byte_seq >= (_dbus_string_get_length (data) - 4))
01156     {
01157       /* reset byte count */
01158       _dbus_assert (iter->depth == (base_depth + 1));
01159       iter_recurse (iter);
01160       _dbus_assert (iter->depth == (base_depth + 2));
01161       iter_set_sequence (iter, 0);
01162       iter_unrecurse (iter);
01163       _dbus_assert (iter->depth == (base_depth + 1));
01164       iter_next (iter);
01165       goto next_change;
01166     }
01167   
01168   _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4));
01169 
01170   byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
01171   
01172   v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL);
01173 
01174   change = &uint32_changes[change_seq];
01175 
01176   if (change->type == CHANGE_TYPE_ADJUST)
01177     {
01178       v_UINT32 += (int) change->value;
01179     }
01180   else
01181     {
01182       v_UINT32 = change->value;
01183     }
01184 
01185 #if 0
01186   printf ("body %d change %d pos %d ",
01187           body_seq, change_seq, byte_seq);
01188 
01189   if (change->type == CHANGE_TYPE_ADJUST)
01190     printf ("adjust by %d", (int) change->value);
01191   else
01192     printf ("set to %u", change->value);
01193   
01194   printf (" \t%u -> %u\n",
01195           _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL),
01196           v_UINT32);
01197 #endif
01198   
01199   _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order);
01200   *expected_validity = DBUS_VALIDITY_UNKNOWN;
01201 
01202   _dbus_assert (iter->depth == (base_depth + 1));
01203   iter_unrecurse (iter);
01204   _dbus_assert (iter->depth == (base_depth + 0));
01205           
01206   return TRUE;
01207 }
01208 
01209 typedef struct
01210 {
01211   const char *name;
01212   DBusMessageGeneratorFunc func;  
01213 } DBusMessageGenerator;
01214 
01215 static const DBusMessageGenerator generators[] = {
01216   { "trivial example of each message type", generate_trivial },
01217   { "assorted arguments", generate_many_bodies },
01218   { "assorted special cases", generate_special },
01219   { "each uint32 modified", generate_uint32_changed },
01220   { "wrong body lengths", generate_wrong_length },
01221   { "each byte modified", generate_byte_changed },
01222 #if 0
01223   /* This is really expensive and doesn't add too much coverage */
01224   { "change each typecode", generate_typecode_changed }
01225 #endif
01226 };
01227 
01228 void
01229 _dbus_message_data_free (DBusMessageData *data)
01230 {
01231   _dbus_string_free (&data->data);
01232 }
01233 
01234 void
01235 _dbus_message_data_iter_init (DBusMessageDataIter *iter)
01236 {
01237   int i;
01238   
01239   iter->depth = 0;
01240   i = 0;
01241   while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
01242     {
01243       iter->sequence_nos[i] = 0;
01244       ++i;
01245     }
01246   iter->count = 0;
01247 }
01248 
01249 dbus_bool_t
01250 _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter,
01251                                       DBusMessageData     *data)
01252 {
01253   DBusMessageGeneratorFunc func;
01254   int generator;
01255 
01256  restart:
01257   generator = iter_get_sequence (iter);
01258   
01259   if (generator == _DBUS_N_ELEMENTS (generators))
01260     return FALSE;
01261 
01262   iter_recurse (iter);
01263   
01264   if (iter_first_in_series (iter))
01265     {
01266       printf (" testing message loading: %s ", generators[generator].name);
01267       fflush (stdout);
01268     }
01269   
01270   func = generators[generator].func;
01271 
01272   if (!_dbus_string_init (&data->data))
01273     _dbus_assert_not_reached ("oom");
01274   
01275   if ((*func)(iter, &data->data, &data->expected_validity))
01276     ;
01277   else
01278     {
01279       iter_set_sequence (iter, 0);
01280       iter_unrecurse (iter);
01281       iter_next (iter); /* next generator */
01282       _dbus_string_free (&data->data);
01283       printf ("%d test loads cumulative\n", iter->count);
01284       goto restart;
01285     }
01286   iter_unrecurse (iter);
01287 
01288   iter->count += 1;
01289   return TRUE;
01290 }
01291 
01292 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
01293 
01294 #endif /* DBUS_BUILD_TESTS */