1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-message-factory.c Generator of valid and invalid message data for test suite
3 *
4 * Copyright (C) 2005 Red Hat Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23#include <config.h>
24
25#ifndef DOXYGEN_SHOULD_SKIP_THIS
26
27#ifdef DBUS_BUILD_TESTS
28#include "dbus-message-factory.h"
29#include "dbus-message-private.h"
30#include "dbus-signature.h"
31#include "dbus-test.h"
32#include <stdio.h>
33
34typedef enum
35  {
36    CHANGE_TYPE_ADJUST,
37    CHANGE_TYPE_ABSOLUTE
38  } ChangeType;
39
40#define BYTE_ORDER_OFFSET  0
41#define TYPE_OFFSET        1
42#define BODY_LENGTH_OFFSET 4
43#define FIELDS_ARRAY_LENGTH_OFFSET 12
44
45static void
46iter_recurse (DBusMessageDataIter *iter)
47{
48  iter->depth += 1;
49  _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING);
50  _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
51}
52
53static int
54iter_get_sequence (DBusMessageDataIter *iter)
55{
56  _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
57  return iter->sequence_nos[iter->depth];
58}
59
60static void
61iter_set_sequence (DBusMessageDataIter *iter,
62                   int                  sequence)
63{
64  _dbus_assert (sequence >= 0);
65  iter->sequence_nos[iter->depth] = sequence;
66}
67
68static void
69iter_unrecurse (DBusMessageDataIter *iter)
70{
71  iter->depth -= 1;
72  _dbus_assert (iter->depth >= 0);
73}
74
75static void
76iter_next (DBusMessageDataIter *iter)
77{
78  iter->sequence_nos[iter->depth] += 1;
79}
80
81static dbus_bool_t
82iter_first_in_series (DBusMessageDataIter *iter)
83{
84  int i;
85
86  i = iter->depth;
87  while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
88    {
89      if (iter->sequence_nos[i] != 0)
90        return FALSE;
91      ++i;
92    }
93  return TRUE;
94}
95
96typedef dbus_bool_t (* DBusInnerGeneratorFunc)   (DBusMessageDataIter *iter,
97                                                  DBusMessage        **message_p);
98typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter,
99                                                  DBusString          *data,
100                                                  DBusValidity        *expected_validity);
101
102static void
103set_reply_serial (DBusMessage *message)
104{
105  if (message == NULL)
106    _dbus_assert_not_reached ("oom");
107  if (!dbus_message_set_reply_serial (message, 100))
108    _dbus_assert_not_reached ("oom");
109}
110
111static dbus_bool_t
112generate_trivial_inner (DBusMessageDataIter *iter,
113                        DBusMessage        **message_p)
114{
115  DBusMessage *message;
116
117  switch (iter_get_sequence (iter))
118    {
119    case 0:
120      message = dbus_message_new_method_call ("org.freedesktop.TextEditor",
121                                              "/foo/bar",
122                                              "org.freedesktop.DocumentFactory",
123                                              "Create");
124      break;
125    case 1:
126      message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
127      set_reply_serial (message);
128      break;
129    case 2:
130      message = dbus_message_new_signal ("/foo/bar",
131                                         "org.freedesktop.DocumentFactory",
132                                         "Created");
133      break;
134    case 3:
135      message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
136
137      if (!dbus_message_set_error_name (message,
138                                        "org.freedesktop.TestErrorName"))
139        _dbus_assert_not_reached ("oom");
140
141      {
142        DBusMessageIter iter;
143        const char *v_STRING = "This is an error";
144
145        dbus_message_iter_init_append (message, &iter);
146        if (!dbus_message_iter_append_basic (&iter,
147                                             DBUS_TYPE_STRING,
148                                             &v_STRING))
149          _dbus_assert_not_reached ("oom");
150      }
151
152      set_reply_serial (message);
153      break;
154    default:
155      return FALSE;
156    }
157
158  if (message == NULL)
159    _dbus_assert_not_reached ("oom");
160
161  *message_p = message;
162
163  return TRUE;
164}
165
166static dbus_bool_t
167generate_many_bodies_inner (DBusMessageDataIter *iter,
168                            DBusMessage        **message_p)
169{
170  DBusMessage *message;
171  DBusString signature;
172  DBusString body;
173  char byte_order;
174
175  /* Keeping this small makes things go faster */
176  message = dbus_message_new_method_call ("o.z.F",
177                                          "/",
178                                          "o.z.B",
179                                          "Nah");
180  if (message == NULL)
181    _dbus_assert_not_reached ("oom");
182
183  byte_order = _dbus_header_get_byte_order (&message->header);
184
185  set_reply_serial (message);
186
187  if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
188    _dbus_assert_not_reached ("oom");
189
190  if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter),
191                                                byte_order,
192                                                &signature, &body))
193    {
194      const char *v_SIGNATURE;
195
196      v_SIGNATURE = _dbus_string_get_const_data (&signature);
197      if (!_dbus_header_set_field_basic (&message->header,
198                                         DBUS_HEADER_FIELD_SIGNATURE,
199                                         DBUS_TYPE_SIGNATURE,
200                                         &v_SIGNATURE))
201        _dbus_assert_not_reached ("oom");
202
203      if (!_dbus_string_move (&body, 0, &message->body, 0))
204        _dbus_assert_not_reached ("oom");
205
206      _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET,
207                                _dbus_string_get_length (&message->body),
208                                byte_order);
209
210      *message_p = message;
211    }
212  else
213    {
214      dbus_message_unref (message);
215      *message_p = NULL;
216    }
217
218  _dbus_string_free (&signature);
219  _dbus_string_free (&body);
220
221  return *message_p != NULL;
222}
223
224static void
225generate_from_message (DBusString            *data,
226                       DBusValidity          *expected_validity,
227                       DBusMessage           *message)
228{
229  dbus_message_set_serial (message, 1);
230  dbus_message_lock (message);
231
232  *expected_validity = DBUS_VALID;
233
234  /* move for efficiency, since we'll nuke the message anyway */
235  if (!_dbus_string_move (&message->header.data, 0,
236                          data, 0))
237    _dbus_assert_not_reached ("oom");
238
239  if (!_dbus_string_copy (&message->body, 0,
240                          data, _dbus_string_get_length (data)))
241    _dbus_assert_not_reached ("oom");
242}
243
244static dbus_bool_t
245generate_outer (DBusMessageDataIter   *iter,
246                DBusString            *data,
247                DBusValidity          *expected_validity,
248                DBusInnerGeneratorFunc func)
249{
250  DBusMessage *message;
251
252  message = NULL;
253  if (!(*func)(iter, &message))
254    return FALSE;
255
256  iter_next (iter);
257
258  _dbus_assert (message != NULL);
259
260  generate_from_message (data, expected_validity, message);
261
262  dbus_message_unref (message);
263
264  return TRUE;
265}
266
267static dbus_bool_t
268generate_trivial (DBusMessageDataIter   *iter,
269                  DBusString            *data,
270                  DBusValidity          *expected_validity)
271{
272  return generate_outer (iter, data, expected_validity,
273                         generate_trivial_inner);
274}
275
276static dbus_bool_t
277generate_many_bodies (DBusMessageDataIter   *iter,
278                      DBusString            *data,
279                      DBusValidity          *expected_validity)
280{
281  return generate_outer (iter, data, expected_validity,
282                         generate_many_bodies_inner);
283}
284
285static DBusMessage*
286simple_method_call (void)
287{
288  DBusMessage *message;
289  /* Keeping this small makes stuff go faster */
290  message = dbus_message_new_method_call ("o.b.Q",
291                                          "/f/b",
292                                          "o.b.Z",
293                                          "Fro");
294  if (message == NULL)
295    _dbus_assert_not_reached ("oom");
296  return message;
297}
298
299static DBusMessage*
300simple_signal (void)
301{
302  DBusMessage *message;
303  message = dbus_message_new_signal ("/f/b",
304                                     "o.b.Z",
305                                     "Fro");
306  if (message == NULL)
307    _dbus_assert_not_reached ("oom");
308  return message;
309}
310
311static DBusMessage*
312simple_method_return (void)
313{
314  DBusMessage *message;
315  message =  dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
316  if (message == NULL)
317    _dbus_assert_not_reached ("oom");
318
319  set_reply_serial (message);
320
321  return message;
322}
323
324static DBusMessage*
325simple_error (void)
326{
327  DBusMessage *message;
328  message =  dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
329  if (message == NULL)
330    _dbus_assert_not_reached ("oom");
331
332  if (!dbus_message_set_error_name (message, "foo.bar"))
333    _dbus_assert_not_reached ("oom");
334
335  set_reply_serial (message);
336
337  return message;
338}
339
340static DBusMessage*
341message_with_nesting_levels (int levels)
342{
343  DBusMessage *message;
344  dbus_int32_t v_INT32;
345  DBusMessageIter *parents;
346  DBusMessageIter *children;
347  int i;
348
349  /* If levels is higher it breaks sig_refcount in DBusMessageRealIter
350   * in dbus-message.c, this assert is just to help you know you need
351   * to fix that if you hit it
352   */
353  _dbus_assert (levels < 256);
354
355  parents = dbus_new(DBusMessageIter, levels + 1);
356  children = dbus_new(DBusMessageIter, levels + 1);
357
358  v_INT32 = 42;
359  message = simple_method_call ();
360
361  i = 0;
362  dbus_message_iter_init_append (message, &parents[i]);
363  while (i < levels)
364    {
365      dbus_message_iter_open_container (&parents[i], DBUS_TYPE_VARIANT,
366                                        i == (levels - 1) ?
367                                        DBUS_TYPE_INT32_AS_STRING :
368                                        DBUS_TYPE_VARIANT_AS_STRING,
369                                        &children[i]);
370      ++i;
371      parents[i] = children[i-1];
372    }
373  --i;
374  dbus_message_iter_append_basic (&children[i], DBUS_TYPE_INT32, &v_INT32);
375  while (i >= 0)
376    {
377      dbus_message_iter_close_container (&parents[i], &children[i]);
378      --i;
379    }
380
381  dbus_free(parents);
382  dbus_free(children);
383
384  return message;
385}
386
387static dbus_bool_t
388generate_special (DBusMessageDataIter   *iter,
389                  DBusString            *data,
390                  DBusValidity          *expected_validity)
391{
392  int item_seq;
393  DBusMessage *message;
394  int pos;
395  dbus_int32_t v_INT32;
396
397  _dbus_assert (_dbus_string_get_length (data) == 0);
398
399  message = NULL;
400  pos = -1;
401  v_INT32 = 42;
402  item_seq = iter_get_sequence (iter);
403
404  if (item_seq == 0)
405    {
406      message = simple_method_call ();
407      if (!dbus_message_append_args (message,
408                                     DBUS_TYPE_INT32, &v_INT32,
409                                     DBUS_TYPE_INT32, &v_INT32,
410                                     DBUS_TYPE_INT32, &v_INT32,
411                                     DBUS_TYPE_INVALID))
412        _dbus_assert_not_reached ("oom");
413
414      _dbus_header_get_field_raw (&message->header,
415                                  DBUS_HEADER_FIELD_SIGNATURE,
416                                  NULL, &pos);
417      generate_from_message (data, expected_validity, message);
418
419      /* set an invalid typecode */
420      _dbus_string_set_byte (data, pos + 1, '$');
421
422      *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE;
423    }
424  else if (item_seq == 1)
425    {
426      char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2];
427      const char *v_STRING;
428      int i;
429
430      message = simple_method_call ();
431      if (!dbus_message_append_args (message,
432                                     DBUS_TYPE_INT32, &v_INT32,
433                                     DBUS_TYPE_INT32, &v_INT32,
434                                     DBUS_TYPE_INT32, &v_INT32,
435                                     DBUS_TYPE_INVALID))
436        _dbus_assert_not_reached ("oom");
437
438      i = 0;
439      while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
440        {
441          long_sig[i] = DBUS_TYPE_ARRAY;
442          ++i;
443        }
444      long_sig[i] = DBUS_TYPE_INVALID;
445
446      v_STRING = long_sig;
447      if (!_dbus_header_set_field_basic (&message->header,
448                                         DBUS_HEADER_FIELD_SIGNATURE,
449                                         DBUS_TYPE_SIGNATURE,
450                                         &v_STRING))
451        _dbus_assert_not_reached ("oom");
452
453      _dbus_header_get_field_raw (&message->header,
454                                  DBUS_HEADER_FIELD_SIGNATURE,
455                                  NULL, &pos);
456      generate_from_message (data, expected_validity, message);
457
458      *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
459    }
460  else if (item_seq == 2)
461    {
462      char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4];
463      const char *v_STRING;
464      int i;
465
466      message = simple_method_call ();
467      if (!dbus_message_append_args (message,
468                                     DBUS_TYPE_INT32, &v_INT32,
469                                     DBUS_TYPE_INT32, &v_INT32,
470                                     DBUS_TYPE_INT32, &v_INT32,
471                                     DBUS_TYPE_INVALID))
472        _dbus_assert_not_reached ("oom");
473
474      i = 0;
475      while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
476        {
477          long_sig[i] = DBUS_STRUCT_BEGIN_CHAR;
478          ++i;
479        }
480
481      long_sig[i] = DBUS_TYPE_INT32;
482      ++i;
483
484      while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3))
485        {
486          long_sig[i] = DBUS_STRUCT_END_CHAR;
487          ++i;
488        }
489      long_sig[i] = DBUS_TYPE_INVALID;
490
491      v_STRING = long_sig;
492      if (!_dbus_header_set_field_basic (&message->header,
493                                         DBUS_HEADER_FIELD_SIGNATURE,
494                                         DBUS_TYPE_SIGNATURE,
495                                         &v_STRING))
496        _dbus_assert_not_reached ("oom");
497
498      _dbus_header_get_field_raw (&message->header,
499                                  DBUS_HEADER_FIELD_SIGNATURE,
500                                  NULL, &pos);
501      generate_from_message (data, expected_validity, message);
502
503      *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
504    }
505  else if (item_seq == 3)
506    {
507      message = simple_method_call ();
508      if (!dbus_message_append_args (message,
509                                     DBUS_TYPE_INT32, &v_INT32,
510                                     DBUS_TYPE_INT32, &v_INT32,
511                                     DBUS_TYPE_INT32, &v_INT32,
512                                     DBUS_TYPE_INVALID))
513        _dbus_assert_not_reached ("oom");
514
515      _dbus_header_get_field_raw (&message->header,
516                                  DBUS_HEADER_FIELD_SIGNATURE,
517                                  NULL, &pos);
518      generate_from_message (data, expected_validity, message);
519
520      _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
521
522      *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
523    }
524  else if (item_seq == 4)
525    {
526      message = simple_method_call ();
527      if (!dbus_message_append_args (message,
528                                     DBUS_TYPE_INT32, &v_INT32,
529                                     DBUS_TYPE_INT32, &v_INT32,
530                                     DBUS_TYPE_INT32, &v_INT32,
531                                     DBUS_TYPE_INVALID))
532        _dbus_assert_not_reached ("oom");
533
534      _dbus_header_get_field_raw (&message->header,
535                                  DBUS_HEADER_FIELD_SIGNATURE,
536                                  NULL, &pos);
537      generate_from_message (data, expected_validity, message);
538
539      _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR);
540
541      *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
542    }
543  else if (item_seq == 5)
544    {
545      message = simple_method_call ();
546      if (!dbus_message_append_args (message,
547                                     DBUS_TYPE_INT32, &v_INT32,
548                                     DBUS_TYPE_INT32, &v_INT32,
549                                     DBUS_TYPE_INT32, &v_INT32,
550                                     DBUS_TYPE_INVALID))
551        _dbus_assert_not_reached ("oom");
552
553      _dbus_header_get_field_raw (&message->header,
554                                  DBUS_HEADER_FIELD_SIGNATURE,
555                                  NULL, &pos);
556      generate_from_message (data, expected_validity, message);
557
558      _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
559      _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR);
560
561      *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
562    }
563  else if (item_seq == 6)
564    {
565      message = simple_method_call ();
566      generate_from_message (data, expected_validity, message);
567
568      _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID);
569
570      *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE;
571    }
572  else if (item_seq == 7)
573    {
574      /* Messages of unknown type are considered valid */
575      message = simple_method_call ();
576      generate_from_message (data, expected_validity, message);
577
578      _dbus_string_set_byte (data, TYPE_OFFSET, 100);
579
580      *expected_validity = DBUS_VALID;
581    }
582  else if (item_seq == 8)
583    {
584      char byte_order;
585
586      message = simple_method_call ();
587      byte_order = _dbus_header_get_byte_order (&message->header);
588      generate_from_message (data, expected_validity, message);
589
590      _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
591                                DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
592                                byte_order);
593      _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET,
594                                DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
595                                byte_order);
596      *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG;
597    }
598  else if (item_seq == 9)
599    {
600      const char *v_STRING = "not a valid bus name";
601      message = simple_method_call ();
602
603      if (!_dbus_header_set_field_basic (&message->header,
604                                         DBUS_HEADER_FIELD_SENDER,
605                                         DBUS_TYPE_STRING, &v_STRING))
606        _dbus_assert_not_reached ("oom");
607
608      generate_from_message (data, expected_validity, message);
609
610      *expected_validity = DBUS_INVALID_BAD_SENDER;
611    }
612  else if (item_seq == 10)
613    {
614      message = simple_method_call ();
615
616      if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL))
617        _dbus_assert_not_reached ("oom");
618
619      generate_from_message (data, expected_validity, message);
620
621      *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE;
622    }
623  else if (item_seq == 11)
624    {
625      message = simple_method_call ();
626
627      if (!dbus_message_set_path (message, DBUS_PATH_LOCAL))
628        _dbus_assert_not_reached ("oom");
629
630      generate_from_message (data, expected_validity, message);
631
632      *expected_validity = DBUS_INVALID_USES_LOCAL_PATH;
633    }
634  else if (item_seq == 12)
635    {
636      /* Method calls don't have to have interface */
637      message = simple_method_call ();
638
639      if (!dbus_message_set_interface (message, NULL))
640        _dbus_assert_not_reached ("oom");
641
642      generate_from_message (data, expected_validity, message);
643
644      *expected_validity = DBUS_VALID;
645    }
646  else if (item_seq == 13)
647    {
648      /* Signals require an interface */
649      message = simple_signal ();
650
651      if (!dbus_message_set_interface (message, NULL))
652        _dbus_assert_not_reached ("oom");
653
654      generate_from_message (data, expected_validity, message);
655
656      *expected_validity = DBUS_INVALID_MISSING_INTERFACE;
657    }
658  else if (item_seq == 14)
659    {
660      message = simple_method_return ();
661
662      if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL))
663        _dbus_assert_not_reached ("oom");
664
665      generate_from_message (data, expected_validity, message);
666
667      *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL;
668    }
669  else if (item_seq == 15)
670    {
671      message = simple_error ();
672
673      if (!dbus_message_set_error_name (message, NULL))
674        _dbus_assert_not_reached ("oom");
675
676      generate_from_message (data, expected_validity, message);
677
678      *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME;
679    }
680  else if (item_seq == 16)
681    {
682      char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+10];
683      const char *v_STRING;
684      int i;
685      int n_begins;
686
687      message = simple_method_call ();
688      if (!dbus_message_append_args (message,
689                                     DBUS_TYPE_INT32, &v_INT32,
690                                     DBUS_TYPE_INT32, &v_INT32,
691                                     DBUS_TYPE_INT32, &v_INT32,
692                                     DBUS_TYPE_INVALID))
693        _dbus_assert_not_reached ("oom");
694
695      i = 0;
696      while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3))
697        {
698          long_sig[i] = DBUS_TYPE_ARRAY;
699          ++i;
700          long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR;
701          ++i;
702          long_sig[i] = DBUS_TYPE_INT32;
703          ++i;
704        }
705      n_begins = i / 3;
706
707      long_sig[i] = DBUS_TYPE_INT32;
708      ++i;
709
710      while (n_begins > 0)
711        {
712          long_sig[i] = DBUS_DICT_ENTRY_END_CHAR;
713          ++i;
714          n_begins -= 1;
715        }
716      long_sig[i] = DBUS_TYPE_INVALID;
717
718      v_STRING = long_sig;
719      if (!_dbus_header_set_field_basic (&message->header,
720                                         DBUS_HEADER_FIELD_SIGNATURE,
721                                         DBUS_TYPE_SIGNATURE,
722                                         &v_STRING))
723        _dbus_assert_not_reached ("oom");
724
725      _dbus_header_get_field_raw (&message->header,
726                                  DBUS_HEADER_FIELD_SIGNATURE,
727                                  NULL, &pos);
728      generate_from_message (data, expected_validity, message);
729
730      *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
731    }
732  else if (item_seq == 17)
733    {
734      message = simple_method_call ();
735      if (!dbus_message_append_args (message,
736                                     DBUS_TYPE_INT32, &v_INT32,
737                                     DBUS_TYPE_INT32, &v_INT32,
738                                     DBUS_TYPE_INT32, &v_INT32,
739                                     DBUS_TYPE_INVALID))
740        _dbus_assert_not_reached ("oom");
741
742      _dbus_header_get_field_raw (&message->header,
743                                  DBUS_HEADER_FIELD_SIGNATURE,
744                                  NULL, &pos);
745      generate_from_message (data, expected_validity, message);
746
747      _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
748      _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
749
750      *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
751    }
752  else if (item_seq == 18)
753    {
754      message = simple_method_call ();
755      if (!dbus_message_append_args (message,
756                                     DBUS_TYPE_INT32, &v_INT32,
757                                     DBUS_TYPE_INT32, &v_INT32,
758                                     DBUS_TYPE_INT32, &v_INT32,
759                                     DBUS_TYPE_INVALID))
760        _dbus_assert_not_reached ("oom");
761
762      _dbus_header_get_field_raw (&message->header,
763                                  DBUS_HEADER_FIELD_SIGNATURE,
764                                  NULL, &pos);
765      generate_from_message (data, expected_validity, message);
766
767      _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR);
768
769      *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
770    }
771  else if (item_seq == 19)
772    {
773      message = simple_method_call ();
774      if (!dbus_message_append_args (message,
775                                     DBUS_TYPE_INT32, &v_INT32,
776                                     DBUS_TYPE_INT32, &v_INT32,
777                                     DBUS_TYPE_INT32, &v_INT32,
778                                     DBUS_TYPE_INVALID))
779        _dbus_assert_not_reached ("oom");
780
781      _dbus_header_get_field_raw (&message->header,
782                                  DBUS_HEADER_FIELD_SIGNATURE,
783                                  NULL, &pos);
784      generate_from_message (data, expected_validity, message);
785
786      _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
787      _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
788      _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR);
789
790      *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
791    }
792  else if (item_seq == 20)
793    {
794      /* 64 levels of nesting is OK */
795      message = message_with_nesting_levels(64);
796
797      generate_from_message (data, expected_validity, message);
798
799      *expected_validity = DBUS_VALID;
800    }
801  else if (item_seq == 21)
802    {
803      /* 65 levels of nesting is not OK */
804      message = message_with_nesting_levels(65);
805
806      generate_from_message (data, expected_validity, message);
807
808      *expected_validity = DBUS_INVALID_NESTED_TOO_DEEPLY;
809    }
810  else
811    {
812      return FALSE;
813    }
814
815  if (message)
816    dbus_message_unref (message);
817
818  iter_next (iter);
819  return TRUE;
820}
821
822static dbus_bool_t
823generate_wrong_length (DBusMessageDataIter *iter,
824                       DBusString          *data,
825                       DBusValidity        *expected_validity)
826{
827  int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1,
828                    1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 };
829  int adjust;
830  int len_seq;
831
832 restart:
833  len_seq = iter_get_sequence (iter);
834  if (len_seq == _DBUS_N_ELEMENTS (lengths))
835    return FALSE;
836
837  _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths));
838
839  iter_recurse (iter);
840  if (!generate_many_bodies (iter, data, expected_validity))
841    {
842      iter_set_sequence (iter, 0); /* reset to first body */
843      iter_unrecurse (iter);
844      iter_next (iter);            /* next length adjustment */
845      goto restart;
846    }
847  iter_unrecurse (iter);
848
849  adjust = lengths[len_seq];
850
851  if (adjust < 0)
852    {
853      if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE)
854        _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE);
855      else
856        _dbus_string_shorten (data, - adjust);
857      *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON;
858    }
859  else
860    {
861      if (!_dbus_string_lengthen (data, adjust))
862        _dbus_assert_not_reached ("oom");
863      *expected_validity = DBUS_INVALID_TOO_MUCH_DATA;
864    }
865
866  /* Fixup lengths */
867  {
868    int old_body_len;
869    int new_body_len;
870    int byte_order;
871
872    _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE);
873
874    byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
875    old_body_len = _dbus_marshal_read_uint32 (data,
876                                              BODY_LENGTH_OFFSET,
877                                              byte_order,
878                                              NULL);
879    _dbus_assert (old_body_len < _dbus_string_get_length (data));
880    new_body_len = old_body_len + adjust;
881    if (new_body_len < 0)
882      {
883        new_body_len = 0;
884        /* we just munged the header, and aren't sure how */
885        *expected_validity = DBUS_VALIDITY_UNKNOWN;
886      }
887
888    _dbus_verbose ("changing body len from %u to %u by adjust %d\n",
889                   old_body_len, new_body_len, adjust);
890
891    _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
892                              new_body_len,
893                              byte_order);
894  }
895
896  return TRUE;
897}
898
899static dbus_bool_t
900generate_byte_changed (DBusMessageDataIter *iter,
901                       DBusString          *data,
902                       DBusValidity        *expected_validity)
903{
904  int byte_seq;
905  int v_BYTE;
906
907  /* This is a little convoluted to make the bodies the
908   * outer loop and each byte of each body the inner
909   * loop
910   */
911
912 restart:
913  if (!generate_many_bodies (iter, data, expected_validity))
914    return FALSE;
915
916  iter_recurse (iter);
917  byte_seq = iter_get_sequence (iter);
918  iter_next (iter);
919  iter_unrecurse (iter);
920
921  if (byte_seq == _dbus_string_get_length (data))
922    {
923      _dbus_string_set_length (data, 0);
924      /* reset byte count */
925      iter_recurse (iter);
926      iter_set_sequence (iter, 0);
927      iter_unrecurse (iter);
928      goto restart;
929    }
930  else
931    {
932      /* Undo the "next" in generate_many_bodies */
933      iter_set_sequence (iter, iter_get_sequence (iter) - 1);
934    }
935
936  _dbus_assert (byte_seq < _dbus_string_get_length (data));
937  v_BYTE = _dbus_string_get_byte (data, byte_seq);
938  v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */
939  _dbus_string_set_byte (data, byte_seq, v_BYTE);
940  *expected_validity = DBUS_VALIDITY_UNKNOWN;
941
942  return TRUE;
943}
944
945#if 0
946/* This is really expensive and doesn't add too much coverage */
947
948static dbus_bool_t
949find_next_typecode (DBusMessageDataIter *iter,
950                    DBusString          *data,
951                    DBusValidity        *expected_validity)
952{
953  int body_seq;
954  int byte_seq;
955  int base_depth;
956
957  base_depth = iter->depth;
958
959 restart:
960  _dbus_assert (iter->depth == (base_depth + 0));
961  _dbus_string_set_length (data, 0);
962
963  body_seq = iter_get_sequence (iter);
964
965  if (!generate_many_bodies (iter, data, expected_validity))
966    return FALSE;
967  /* Undo the "next" in generate_many_bodies */
968  iter_set_sequence (iter, body_seq);
969
970  iter_recurse (iter);
971  while (TRUE)
972    {
973      _dbus_assert (iter->depth == (base_depth + 1));
974
975      byte_seq = iter_get_sequence (iter);
976
977      _dbus_assert (byte_seq <= _dbus_string_get_length (data));
978
979      if (byte_seq == _dbus_string_get_length (data))
980        {
981          /* reset byte count */
982          iter_set_sequence (iter, 0);
983          iter_unrecurse (iter);
984          _dbus_assert (iter->depth == (base_depth + 0));
985          iter_next (iter); /* go to the next body */
986          goto restart;
987        }
988
989      _dbus_assert (byte_seq < _dbus_string_get_length (data));
990
991      if (dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
992        break;
993      else
994        iter_next (iter);
995    }
996
997  _dbus_assert (byte_seq == iter_get_sequence (iter));
998  _dbus_assert (byte_seq < _dbus_string_get_length (data));
999
1000  iter_unrecurse (iter);
1001
1002  _dbus_assert (iter->depth == (base_depth + 0));
1003
1004  return TRUE;
1005}
1006
1007static const int typecodes[] = {
1008  DBUS_TYPE_INVALID,
1009  DBUS_TYPE_BYTE,
1010  DBUS_TYPE_BOOLEAN,
1011  DBUS_TYPE_INT16,
1012  DBUS_TYPE_UINT16,
1013  DBUS_TYPE_INT32,
1014  DBUS_TYPE_UINT32,
1015  DBUS_TYPE_INT64,
1016  DBUS_TYPE_UINT64,
1017  DBUS_TYPE_DOUBLE,
1018  DBUS_TYPE_STRING,
1019  DBUS_TYPE_OBJECT_PATH,
1020  DBUS_TYPE_SIGNATURE,
1021  DBUS_TYPE_ARRAY,
1022  DBUS_TYPE_VARIANT,
1023  DBUS_STRUCT_BEGIN_CHAR,
1024  DBUS_STRUCT_END_CHAR,
1025  DBUS_DICT_ENTRY_BEGIN_CHAR,
1026  DBUS_DICT_ENTRY_END_CHAR,
1027  DBUS_TYPE_UNIX_FD,
1028  255 /* random invalid typecode */
1029};
1030
1031static dbus_bool_t
1032generate_typecode_changed (DBusMessageDataIter *iter,
1033                           DBusString          *data,
1034                           DBusValidity        *expected_validity)
1035{
1036  int byte_seq;
1037  int typecode_seq;
1038  int base_depth;
1039
1040  base_depth = iter->depth;
1041
1042 restart:
1043  _dbus_assert (iter->depth == (base_depth + 0));
1044  _dbus_string_set_length (data, 0);
1045
1046  if (!find_next_typecode (iter, data, expected_validity))
1047    return FALSE;
1048
1049  iter_recurse (iter);
1050  byte_seq = iter_get_sequence (iter);
1051
1052  _dbus_assert (byte_seq < _dbus_string_get_length (data));
1053
1054  iter_recurse (iter);
1055  typecode_seq = iter_get_sequence (iter);
1056  iter_next (iter);
1057
1058  _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes));
1059
1060  if (typecode_seq == _DBUS_N_ELEMENTS (typecodes))
1061    {
1062      _dbus_assert (iter->depth == (base_depth + 2));
1063      iter_set_sequence (iter, 0); /* reset typecode sequence */
1064      iter_unrecurse (iter);
1065      _dbus_assert (iter->depth == (base_depth + 1));
1066      iter_next (iter); /* go to the next byte_seq */
1067      iter_unrecurse (iter);
1068      _dbus_assert (iter->depth == (base_depth + 0));
1069      goto restart;
1070    }
1071
1072  _dbus_assert (iter->depth == (base_depth + 2));
1073  iter_unrecurse (iter);
1074  _dbus_assert (iter->depth == (base_depth + 1));
1075  iter_unrecurse (iter);
1076  _dbus_assert (iter->depth == (base_depth + 0));
1077
1078#if 0
1079  printf ("Changing byte %d in message %d to %c\n",
1080          byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]);
1081#endif
1082
1083  _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]);
1084  *expected_validity = DBUS_VALIDITY_UNKNOWN;
1085  return TRUE;
1086}
1087#endif
1088
1089typedef struct
1090{
1091  ChangeType type;
1092  dbus_uint32_t value; /* cast to signed for adjusts */
1093} UIntChange;
1094
1095static const UIntChange uint32_changes[] = {
1096  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 },
1097  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 },
1098  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 },
1099  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 },
1100  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 },
1101  { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 },
1102  { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX },
1103  { CHANGE_TYPE_ABSOLUTE, 0 },
1104  { CHANGE_TYPE_ABSOLUTE, 1 },
1105  { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 },
1106  { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 }
1107};
1108
1109static dbus_bool_t
1110generate_uint32_changed (DBusMessageDataIter *iter,
1111                         DBusString          *data,
1112                         DBusValidity        *expected_validity)
1113{
1114  int body_seq;
1115  int byte_seq;
1116  int change_seq;
1117  dbus_uint32_t v_UINT32;
1118  int byte_order;
1119  const UIntChange *change;
1120  int base_depth;
1121
1122  /* Outer loop is each body, next loop is each change,
1123   * inner loop is each change location
1124   */
1125
1126  base_depth = iter->depth;
1127
1128 next_body:
1129  _dbus_assert (iter->depth == (base_depth + 0));
1130  _dbus_string_set_length (data, 0);
1131  body_seq = iter_get_sequence (iter);
1132
1133  if (!generate_many_bodies (iter, data, expected_validity))
1134    return FALSE;
1135
1136  _dbus_assert (iter->depth == (base_depth + 0));
1137
1138  iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */
1139  iter_recurse (iter);
1140 next_change:
1141  _dbus_assert (iter->depth == (base_depth + 1));
1142  change_seq = iter_get_sequence (iter);
1143
1144  if (change_seq == _DBUS_N_ELEMENTS (uint32_changes))
1145    {
1146      /* Reset change count */
1147      iter_set_sequence (iter, 0);
1148      iter_unrecurse (iter);
1149      iter_next (iter);
1150      goto next_body;
1151    }
1152
1153  _dbus_assert (iter->depth == (base_depth + 1));
1154
1155  iter_recurse (iter);
1156  _dbus_assert (iter->depth == (base_depth + 2));
1157  byte_seq = iter_get_sequence (iter);
1158  /* skip 4 bytes at a time */
1159  iter_next (iter);
1160  iter_next (iter);
1161  iter_next (iter);
1162  iter_next (iter);
1163  iter_unrecurse (iter);
1164
1165  _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq);
1166  if (byte_seq >= (_dbus_string_get_length (data) - 4))
1167    {
1168      /* reset byte count */
1169      _dbus_assert (iter->depth == (base_depth + 1));
1170      iter_recurse (iter);
1171      _dbus_assert (iter->depth == (base_depth + 2));
1172      iter_set_sequence (iter, 0);
1173      iter_unrecurse (iter);
1174      _dbus_assert (iter->depth == (base_depth + 1));
1175      iter_next (iter);
1176      goto next_change;
1177    }
1178
1179  _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4));
1180
1181  byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
1182
1183  v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL);
1184
1185  change = &uint32_changes[change_seq];
1186
1187  if (change->type == CHANGE_TYPE_ADJUST)
1188    {
1189      v_UINT32 += (int) change->value;
1190    }
1191  else
1192    {
1193      v_UINT32 = change->value;
1194    }
1195
1196#if 0
1197  printf ("body %d change %d pos %d ",
1198          body_seq, change_seq, byte_seq);
1199
1200  if (change->type == CHANGE_TYPE_ADJUST)
1201    printf ("adjust by %d", (int) change->value);
1202  else
1203    printf ("set to %u", change->value);
1204
1205  printf (" \t%u -> %u\n",
1206          _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL),
1207          v_UINT32);
1208#endif
1209
1210  _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order);
1211  *expected_validity = DBUS_VALIDITY_UNKNOWN;
1212
1213  _dbus_assert (iter->depth == (base_depth + 1));
1214  iter_unrecurse (iter);
1215  _dbus_assert (iter->depth == (base_depth + 0));
1216
1217  return TRUE;
1218}
1219
1220typedef struct
1221{
1222  const char *name;
1223  DBusMessageGeneratorFunc func;
1224} DBusMessageGenerator;
1225
1226static const DBusMessageGenerator generators[] = {
1227  { "trivial example of each message type", generate_trivial },
1228  { "assorted arguments", generate_many_bodies },
1229  { "assorted special cases", generate_special },
1230  { "each uint32 modified", generate_uint32_changed },
1231  { "wrong body lengths", generate_wrong_length },
1232  { "each byte modified", generate_byte_changed },
1233#if 0
1234  /* This is really expensive and doesn't add too much coverage */
1235  { "change each typecode", generate_typecode_changed }
1236#endif
1237};
1238
1239void
1240_dbus_message_data_free (DBusMessageData *data)
1241{
1242  _dbus_string_free (&data->data);
1243}
1244
1245void
1246_dbus_message_data_iter_init (DBusMessageDataIter *iter)
1247{
1248  int i;
1249
1250  iter->depth = 0;
1251  i = 0;
1252  while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
1253    {
1254      iter->sequence_nos[i] = 0;
1255      ++i;
1256    }
1257  iter->count = 0;
1258}
1259
1260dbus_bool_t
1261_dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter,
1262                                      DBusMessageData     *data)
1263{
1264  DBusMessageGeneratorFunc func;
1265  int generator;
1266
1267 restart:
1268  generator = iter_get_sequence (iter);
1269
1270  if (generator == _DBUS_N_ELEMENTS (generators))
1271    return FALSE;
1272
1273  iter_recurse (iter);
1274
1275  if (iter_first_in_series (iter))
1276    {
1277      printf (" testing message loading: %s ", generators[generator].name);
1278      fflush (stdout);
1279    }
1280
1281  func = generators[generator].func;
1282
1283  if (!_dbus_string_init (&data->data))
1284    _dbus_assert_not_reached ("oom");
1285
1286  if ((*func)(iter, &data->data, &data->expected_validity))
1287    ;
1288  else
1289    {
1290      iter_set_sequence (iter, 0);
1291      iter_unrecurse (iter);
1292      iter_next (iter); /* next generator */
1293      _dbus_string_free (&data->data);
1294      printf ("%d test loads cumulative\n", iter->count);
1295      goto restart;
1296    }
1297  iter_unrecurse (iter);
1298
1299  iter->count += 1;
1300  return TRUE;
1301}
1302
1303#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
1304
1305#endif /* DBUS_BUILD_TESTS */
1306