minor cleanup
[platform/upstream/dbus.git] / dbus / dbus-marshal-recursive.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c  Marshalling routines for recursive types
3  *
4  * Copyright (C) 2004, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-marshal-recursive.h"
25 #include "dbus-marshal-basic.h"
26 #include "dbus-internals.h"
27
28 /**
29  * @addtogroup DBusMarshal
30  * @{
31  */
32 #define RECURSIVE_MARSHAL_TRACE 0
33
34 struct DBusTypeReaderClass
35 {
36   const char *name;
37   int         id;         /* index in all_reader_classes */
38   dbus_bool_t types_only; /* only iterates over types, not values */
39   void        (* recurse)          (DBusTypeReader        *sub,
40                                     DBusTypeReader        *parent);
41   dbus_bool_t (* check_finished)   (const DBusTypeReader  *reader);
42   void        (* next)             (DBusTypeReader        *reader,
43                                     int                    current_type);
44   void        (* init_from_mark)   (DBusTypeReader        *reader,
45                                     const DBusTypeMark    *mark);
46 };
47
48 static int
49 first_type_in_signature (const DBusString *str,
50                          int               pos)
51 {
52   int t;
53
54   t = _dbus_string_get_byte (str, pos);
55
56   if (t == DBUS_STRUCT_BEGIN_CHAR)
57     return DBUS_TYPE_STRUCT;
58   else
59     return t;
60 }
61
62 static int
63 element_type_get_alignment (const DBusString *str,
64                             int               pos)
65 {
66   return _dbus_type_get_alignment (first_type_in_signature (str, pos));
67 }
68
69 static void
70 reader_init (DBusTypeReader    *reader,
71              int                byte_order,
72              const DBusString  *type_str,
73              int                type_pos,
74              const DBusString  *value_str,
75              int                value_pos)
76 {
77   reader->byte_order = byte_order;
78   reader->finished = FALSE;
79   reader->type_str = type_str;
80   reader->type_pos = type_pos;
81   reader->value_str = value_str;
82   reader->value_pos = value_pos;
83 }
84
85 static void
86 base_reader_recurse (DBusTypeReader *sub,
87                      DBusTypeReader *parent)
88 {
89   /* point subreader at the same place as parent */
90   reader_init (sub,
91                parent->byte_order,
92                parent->type_str,
93                parent->type_pos,
94                parent->value_str,
95                parent->value_pos);
96 }
97
98 static void
99 struct_types_only_reader_recurse (DBusTypeReader *sub,
100                                   DBusTypeReader *parent)
101 {
102   base_reader_recurse (sub, parent);
103
104   _dbus_assert (_dbus_string_get_byte (sub->type_str,
105                                        sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
106
107   sub->type_pos += 1;
108 }
109
110 static void
111 struct_reader_recurse (DBusTypeReader *sub,
112                        DBusTypeReader *parent)
113 {
114   struct_types_only_reader_recurse (sub, parent);
115
116   /* struct has 8 byte alignment */
117   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
118 }
119
120 static void
121 array_types_only_reader_recurse (DBusTypeReader *sub,
122                                  DBusTypeReader *parent)
123 {
124   base_reader_recurse (sub, parent);
125
126   /* point type_pos at the array element type */
127   sub->type_pos += 1;
128
129   /* Init with values likely to crash things if misused */
130   sub->u.array.start_pos = _DBUS_INT_MAX;
131   sub->array_len_offset = 7;
132 }
133
134 static int
135 array_reader_get_array_len (const DBusTypeReader *reader)
136 {
137   dbus_uint32_t array_len;
138   int len_pos;
139
140   /* array_len_offset is the offset back from start_pos to end of the len */
141   len_pos = reader->u.array.start_pos - ((int)reader->array_len_offset) - 4;
142
143   _dbus_marshal_read_basic (reader->value_str,
144                             len_pos,
145                             DBUS_TYPE_UINT32,
146                             &array_len,
147                             reader->byte_order,
148                             NULL);
149
150   _dbus_verbose ("   reader %p len_pos %d array len %u len_offset %d\n",
151                  reader, len_pos, array_len, reader->array_len_offset);
152
153   _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
154
155   return array_len;
156 }
157
158 static void
159 array_reader_recurse (DBusTypeReader *sub,
160                       DBusTypeReader *parent)
161 {
162   int alignment;
163   int len_pos;
164
165   array_types_only_reader_recurse (sub, parent);
166
167   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
168
169   len_pos = sub->value_pos;
170
171   sub->value_pos += 4; /* for the length */
172
173   alignment = element_type_get_alignment (sub->type_str,
174                                           sub->type_pos);
175
176   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
177
178   sub->u.array.start_pos = sub->value_pos;
179   _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
180   sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
181
182 #if RECURSIVE_MARSHAL_TRACE
183   _dbus_verbose ("    type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
184                  sub,
185                  sub->u.array.start_pos,
186                  sub->array_len_offset,
187                  array_reader_get_array_len (sub),
188                  _dbus_type_to_string (first_type_in_signature (sub->type_str,
189                                                                 sub->type_pos)));
190 #endif
191 }
192
193 static void
194 variant_reader_recurse (DBusTypeReader *sub,
195                         DBusTypeReader *parent)
196 {
197   int sig_len;
198
199   base_reader_recurse (sub, parent);
200
201   /* Variant is 1 byte sig length (without nul), signature with nul,
202    * padding to 8-boundary, then values
203    */
204
205   sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
206
207   sub->type_str = sub->value_str;
208   sub->type_pos = sub->value_pos + 1;
209
210   sub->value_pos = sub->type_pos + sig_len + 1;
211
212   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
213
214 #if RECURSIVE_MARSHAL_TRACE
215   _dbus_verbose ("    type reader %p variant containing '%s'\n",
216                  sub,
217                  _dbus_string_get_const_data_len (sub->type_str,
218                                                   sub->type_pos, 0));
219 #endif
220 }
221
222 static dbus_bool_t
223 array_reader_check_finished (const DBusTypeReader *reader)
224 {
225   int end_pos;
226
227   /* return the array element type if elements remain, and
228    * TYPE_INVALID otherwise
229    */
230
231   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
232
233   _dbus_assert (reader->value_pos <= end_pos);
234   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
235
236   return reader->value_pos == end_pos;
237 }
238
239 static void
240 skip_one_complete_type (const DBusString *type_str,
241                         int              *type_pos)
242 {
243   while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
244     *type_pos += 1;
245
246   if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
247     {
248       int depth;
249       depth = 1;
250       *type_pos += 1;
251       while (depth > 0)
252         {
253           switch (_dbus_string_get_byte (type_str, *type_pos))
254             {
255             case DBUS_STRUCT_BEGIN_CHAR:
256               depth += 1;
257               break;
258             case DBUS_STRUCT_END_CHAR:
259               depth -= 1;
260               break;
261             case DBUS_TYPE_INVALID:
262               _dbus_assert_not_reached ("unbalanced parens in signature");
263               break;
264             }
265           *type_pos += 1;
266         }
267     }
268   else
269     *type_pos += 1;
270 }
271
272 static int
273 find_len_of_complete_type (const DBusString *type_str,
274                            int               type_pos)
275 {
276   int end;
277
278   end = type_pos;
279
280   skip_one_complete_type (type_str, &end);
281
282   return end - type_pos;
283 }
284
285 static void
286 base_reader_next (DBusTypeReader *reader,
287                   int             current_type)
288 {
289   switch (current_type)
290     {
291     case DBUS_TYPE_STRUCT:
292     case DBUS_TYPE_VARIANT:
293       /* Scan forward over the entire container contents */
294       {
295         DBusTypeReader sub;
296
297         /* Recurse into the struct or variant */
298         _dbus_type_reader_recurse (reader, &sub);
299
300         /* Skip everything in this subreader */
301         while (_dbus_type_reader_next (&sub))
302           {
303             /* nothing */;
304           }
305
306         /* Now we are at the end of this container; for variants, the
307          * subreader's type_pos is totally inapplicable (it's in the
308          * value string) but we know that we increment by one past the
309          * DBUS_TYPE_VARIANT
310          */
311         if (current_type == DBUS_TYPE_VARIANT)
312           reader->type_pos += 1;
313         else
314           reader->type_pos = sub.type_pos;
315
316         if (!reader->klass->types_only)
317           reader->value_pos = sub.value_pos;
318       }
319       break;
320
321     case DBUS_TYPE_ARRAY:
322       {
323         if (!reader->klass->types_only)
324           _dbus_marshal_skip_array (reader->value_str,
325                                     first_type_in_signature (reader->type_str,
326                                                              reader->type_pos + 1),
327                                     reader->byte_order,
328                                     &reader->value_pos);
329
330         skip_one_complete_type (reader->type_str, &reader->type_pos);
331       }
332       break;
333
334     default:
335       if (!reader->klass->types_only)
336         _dbus_marshal_skip_basic (reader->value_str,
337                                   current_type, reader->byte_order,
338                                   &reader->value_pos);
339
340       reader->type_pos += 1;
341       break;
342     }
343 }
344
345 static void
346 struct_reader_next (DBusTypeReader *reader,
347                     int             current_type)
348 {
349   int t;
350
351   base_reader_next (reader, current_type);
352
353   /* for STRUCT containers we return FALSE at the end of the struct,
354    * for INVALID we return FALSE at the end of the signature.
355    * In both cases we arrange for get_current_type() to return INVALID
356    * which is defined to happen iff we're at the end (no more next())
357    */
358   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
359   if (t == DBUS_STRUCT_END_CHAR)
360     {
361       reader->type_pos += 1;
362       reader->finished = TRUE;
363     }
364 }
365
366 static void
367 array_types_only_reader_next (DBusTypeReader *reader,
368                               int             current_type)
369 {
370   /* We have one "element" to be iterated over
371    * in each array, which is its element type.
372    * So the finished flag indicates whether we've
373    * iterated over it yet or not.
374    */
375   reader->finished = TRUE;
376 }
377
378 static void
379 array_reader_next (DBusTypeReader *reader,
380                    int             current_type)
381 {
382   /* Skip one array element */
383   int end_pos;
384
385   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
386
387   _dbus_assert (reader->value_pos < end_pos);
388   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
389
390   switch (first_type_in_signature (reader->type_str,
391                                    reader->type_pos))
392     {
393     case DBUS_TYPE_STRUCT:
394     case DBUS_TYPE_VARIANT:
395       {
396         DBusTypeReader sub;
397
398         /* Recurse into the struct or variant */
399         _dbus_type_reader_recurse (reader, &sub);
400
401         /* Skip everything in this element */
402         while (_dbus_type_reader_next (&sub))
403           {
404             /* nothing */;
405           }
406
407         /* Now we are at the end of this element */
408         reader->value_pos = sub.value_pos;
409       }
410       break;
411
412     case DBUS_TYPE_ARRAY:
413       {
414         _dbus_marshal_skip_array (reader->value_str,
415                                   first_type_in_signature (reader->type_str,
416                                                            reader->type_pos + 1),
417                                   reader->byte_order,
418                                   &reader->value_pos);
419       }
420       break;
421
422     default:
423       {
424         _dbus_marshal_skip_basic (reader->value_str,
425                                   current_type, reader->byte_order,
426                                   &reader->value_pos);
427       }
428       break;
429     }
430
431   _dbus_assert (reader->value_pos <= end_pos);
432
433   if (reader->value_pos == end_pos)
434     {
435       skip_one_complete_type (reader->type_str,
436                               &reader->type_pos);
437     }
438 }
439
440 static void
441 array_init_from_mark (DBusTypeReader     *reader,
442                       const DBusTypeMark *mark)
443 {
444   /* Fill in the array-specific fields from the mark. The general
445    * fields are already filled in.
446    */
447   reader->u.array.start_pos = mark->array_start_pos;
448   reader->array_len_offset = mark->array_len_offset;
449 }
450
451 static const DBusTypeReaderClass body_reader_class = {
452   "body", 0,
453   FALSE,
454   NULL, /* body is always toplevel, so doesn't get recursed into */
455   NULL,
456   base_reader_next,
457   NULL
458 };
459
460 static const DBusTypeReaderClass body_types_only_reader_class = {
461   "body types", 1,
462   TRUE,
463   NULL, /* body is always toplevel, so doesn't get recursed into */
464   NULL,
465   base_reader_next,
466   NULL
467 };
468
469 static const DBusTypeReaderClass struct_reader_class = {
470   "struct", 2,
471   FALSE,
472   struct_reader_recurse,
473   NULL,
474   struct_reader_next,
475   NULL
476 };
477
478 static const DBusTypeReaderClass struct_types_only_reader_class = {
479   "struct types", 3,
480   TRUE,
481   struct_types_only_reader_recurse,
482   NULL,
483   struct_reader_next,
484   NULL
485 };
486
487 static const DBusTypeReaderClass array_reader_class = {
488   "array", 4,
489   FALSE,
490   array_reader_recurse,
491   array_reader_check_finished,
492   array_reader_next,
493   array_init_from_mark
494 };
495
496 static const DBusTypeReaderClass array_types_only_reader_class = {
497   "array types", 5,
498   TRUE,
499   array_types_only_reader_recurse,
500   NULL,
501   array_types_only_reader_next,
502   NULL
503 };
504
505 static const DBusTypeReaderClass variant_reader_class = {
506   "variant", 6,
507   FALSE,
508   variant_reader_recurse,
509   NULL,
510   base_reader_next,
511   NULL
512 };
513
514 static const DBusTypeReaderClass const *
515 all_reader_classes[] = {
516   &body_reader_class,
517   &body_types_only_reader_class,
518   &struct_reader_class,
519   &struct_types_only_reader_class,
520   &array_reader_class,
521   &array_types_only_reader_class,
522   &variant_reader_class
523 };
524
525 void
526 _dbus_type_reader_init (DBusTypeReader    *reader,
527                         int                byte_order,
528                         const DBusString  *type_str,
529                         int                type_pos,
530                         const DBusString  *value_str,
531                         int                value_pos)
532 {
533   reader->klass = &body_reader_class;
534
535   reader_init (reader, byte_order, type_str, type_pos,
536                value_str, value_pos);
537
538 #if RECURSIVE_MARSHAL_TRACE
539   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
540                  reader, reader->type_pos, reader->value_pos,
541                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
542 #endif
543 }
544
545 void
546 _dbus_type_reader_init_from_mark (DBusTypeReader     *reader,
547                                   int                 byte_order,
548                                   const DBusString   *type_str,
549                                   const DBusString   *value_str,
550                                   const DBusTypeMark *mark)
551 {
552   reader->klass = all_reader_classes[mark->container_type];
553
554   reader_init (reader, byte_order,
555                mark->type_pos_in_value_str ? value_str : type_str,
556                mark->type_pos,
557                value_str, mark->value_pos);
558
559   if (reader->klass->init_from_mark)
560     (* reader->klass->init_from_mark) (reader, mark);
561
562 #if RECURSIVE_MARSHAL_TRACE
563   _dbus_verbose ("  type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",
564                  reader, reader->type_pos, reader->value_pos,
565                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
566 #endif
567 }
568
569 void
570 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
571                                    const DBusString  *type_str,
572                                    int                type_pos)
573 {
574   reader->klass = &body_types_only_reader_class;
575
576   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
577                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
578
579 #if RECURSIVE_MARSHAL_TRACE
580   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
581                  reader, reader->type_pos,
582                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
583 #endif
584 }
585
586 void
587 _dbus_type_reader_init_types_only_from_mark (DBusTypeReader     *reader,
588                                              const DBusString   *type_str,
589                                              const DBusTypeMark *mark)
590 {
591   reader->klass = all_reader_classes[mark->container_type];
592   _dbus_assert (reader->klass->types_only);
593   _dbus_assert (!mark->type_pos_in_value_str);
594
595   reader_init (reader, DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
596                type_str, mark->type_pos,
597                NULL, _DBUS_INT_MAX /* crashes if we screw up */);
598
599   if (reader->klass->init_from_mark)
600     (* reader->klass->init_from_mark) (reader, mark);
601
602 #if RECURSIVE_MARSHAL_TRACE
603   _dbus_verbose ("  type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",
604                  reader, reader->type_pos,
605                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
606 #endif
607 }
608
609 void
610 _dbus_type_reader_save_mark (const DBusTypeReader *reader,
611                              DBusTypeMark         *mark)
612 {
613   mark->type_pos_in_value_str = (reader->type_str == reader->value_str);
614   mark->container_type = reader->klass->id;
615   _dbus_assert (all_reader_classes[reader->klass->id] == reader->klass);
616
617   mark->type_pos = reader->type_pos;
618   mark->value_pos = reader->value_pos;
619
620   /* these are just junk if the reader isn't really an array of course */
621   mark->array_len_offset = reader->array_len_offset;
622   mark->array_start_pos = reader->u.array.start_pos;
623 }
624
625 int
626 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
627 {
628   int t;
629
630   if (reader->finished ||
631       (reader->klass->check_finished &&
632        (* reader->klass->check_finished) (reader)))
633     t = DBUS_TYPE_INVALID;
634   else
635     t = first_type_in_signature (reader->type_str,
636                                  reader->type_pos);
637
638   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
639   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
640
641 #if 0
642   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
643                  reader, reader->type_pos,
644                  _dbus_type_to_string (t));
645 #endif
646
647   return t;
648 }
649
650 dbus_bool_t
651 _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)
652 {
653   dbus_uint32_t array_len;
654
655   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
656   _dbus_assert (!reader->klass->types_only);
657
658   /* reader is supposed to be at an array child */
659 #if RECURSIVE_MARSHAL_TRACE
660    _dbus_verbose ("checking array len at %d\n", reader->value_pos);
661 #endif
662
663    _dbus_marshal_read_basic (reader->value_str,
664                              reader->value_pos,
665                              DBUS_TYPE_UINT32,
666                              &array_len,
667                              reader->byte_order,
668                              NULL);
669 #if RECURSIVE_MARSHAL_TRACE
670   _dbus_verbose (" ... array len = %d\n", array_len);
671 #endif
672
673   return array_len == 0;
674 }
675
676 void
677 _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
678                               void                    *value)
679 {
680   int t;
681
682   _dbus_assert (!reader->klass->types_only);
683
684   t = _dbus_type_reader_get_current_type (reader);
685
686   _dbus_marshal_read_basic (reader->value_str,
687                             reader->value_pos,
688                             t, value,
689                             reader->byte_order,
690                             NULL);
691
692
693 #if RECURSIVE_MARSHAL_TRACE
694   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
695                  reader, reader->type_pos, reader->value_pos,
696                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
697 #endif
698 }
699
700 dbus_bool_t
701 _dbus_type_reader_read_array_of_basic (const DBusTypeReader    *reader,
702                                        int                      type,
703                                        void                   **array,
704                                        int                     *array_len)
705 {
706   _dbus_assert (!reader->klass->types_only);
707
708 }
709
710 /**
711  * Initialize a new reader pointing to the first type and
712  * corresponding value that's a child of the current container. It's
713  * an error to call this if the current type is a non-container.
714  *
715  * Note that DBusTypeReader traverses values, not types. So if you
716  * have an empty array of array of int, you can't recurse into it. You
717  * can only recurse into each element.
718  *
719  * @param reader the reader
720  * @param sub a reader to init pointing to the first child
721  */
722 void
723 _dbus_type_reader_recurse (DBusTypeReader *reader,
724                            DBusTypeReader *sub)
725 {
726   int t;
727
728   t = first_type_in_signature (reader->type_str, reader->type_pos);
729
730   switch (t)
731     {
732     case DBUS_TYPE_STRUCT:
733       if (reader->klass->types_only)
734         sub->klass = &struct_types_only_reader_class;
735       else
736         sub->klass = &struct_reader_class;
737       break;
738     case DBUS_TYPE_ARRAY:
739       if (reader->klass->types_only)
740         sub->klass = &array_types_only_reader_class;
741       else
742         sub->klass = &array_reader_class;
743       break;
744     case DBUS_TYPE_VARIANT:
745       if (reader->klass->types_only)
746         _dbus_assert_not_reached ("can't recurse into variant typecode");
747       else
748         sub->klass = &variant_reader_class;
749       break;
750     default:
751       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
752 #ifndef DBUS_DISABLE_CHECKS
753       if (t == DBUS_TYPE_INVALID)
754         _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
755 #endif /* DBUS_DISABLE_CHECKS */
756
757       _dbus_assert_not_reached ("don't yet handle recursing into this type");
758     }
759
760   _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
761
762   (* sub->klass->recurse) (sub, reader);
763
764 #if RECURSIVE_MARSHAL_TRACE
765   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
766                  sub, sub->type_pos, sub->value_pos,
767                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
768 #endif
769 }
770
771 /**
772  * Skip to the next value on this "level". e.g. the next field in a
773  * struct, the next value in an array. Returns FALSE at the end of the
774  * current container.
775  *
776  * @param reader the reader
777  * @returns FALSE if nothing more to read at or below this level
778  */
779 dbus_bool_t
780 _dbus_type_reader_next (DBusTypeReader *reader)
781 {
782   int t;
783
784   t = _dbus_type_reader_get_current_type (reader);
785
786 #if RECURSIVE_MARSHAL_TRACE
787   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
788                  reader, reader->type_pos, reader->value_pos,
789                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
790                  _dbus_type_to_string (t));
791 #endif
792
793   if (t == DBUS_TYPE_INVALID)
794     return FALSE;
795
796   (* reader->klass->next) (reader, t);
797
798 #if RECURSIVE_MARSHAL_TRACE
799   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
800                  reader, reader->type_pos, reader->value_pos,
801                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
802                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
803 #endif
804
805   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
806 }
807
808 /**
809  * Check whether there's another value on this "level". e.g. the next
810  * field in a struct, the next value in an array. Returns FALSE at the
811  * end of the current container.
812  *
813  * You probably don't want to use this; it makes for an awkward for/while
814  * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)"
815  *
816  * @param reader the reader
817  * @returns FALSE if nothing more to read at or below this level
818  */
819 dbus_bool_t
820 _dbus_type_reader_has_next (const DBusTypeReader *reader)
821 {
822   /* Not efficient but works for now. */
823   DBusTypeReader copy;
824
825   copy = *reader;
826   return _dbus_type_reader_next (&copy);
827 }
828
829 /**
830  * Gets the string and range of said string containing the signature
831  * of the current value. Essentially a more complete version of
832  * _dbus_type_reader_get_current_type() (returns the full type
833  * rather than only the outside of the onion).
834  *
835  * Note though that the first byte in a struct signature is
836  * #DBUS_STRUCT_BEGIN_CHAR while the current type will be
837  * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the
838  * signature is always the same as the current type. Another
839  * difference is that this function will still return a signature when
840  * inside an empty array; say you recurse into empty array of int32,
841  * the signature is "i" but the current type will always be
842  * #DBUS_TYPE_INVALID since there are no elements to be currently
843  * pointing to.
844  *
845  * @param reader the reader
846  * @param str_p place to return the string with the type in it
847  * @param start_p place to return start of the type
848  * @param len_p place to return the length of the type
849  */
850 void
851 _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
852                                  const DBusString     **str_p,
853                                  int                   *start_p,
854                                  int                   *len_p)
855 {
856   *str_p = reader->type_str;
857   *start_p = reader->type_pos;
858   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
859 }
860
861 static void
862 reader_set_basic_fixed_length (DBusTypeReader *reader,
863                                int             current_type,
864                                const void     *value)
865 {
866   _dbus_marshal_set_basic ((DBusString*) reader->value_str,
867                            reader->value_pos,
868                            current_type,
869                            value,
870                            reader->byte_order,
871                            NULL, NULL);
872 }
873
874 /**
875  * Sets a new value for the basic type pointed to by the reader,
876  * leaving the reader valid to continue reading. Any other readers may
877  * of course be invalidated if you set a variable-length type such as
878  * a string.
879  *
880  * The provided realign_root is the reader to start from when
881  * realigning the data that follows the newly-set value. The reader
882  * parameter must point to a value below the realign_root parameter.
883  * If the type being set is fixed-length, then realign_root may be
884  * #NULL. Only values reachable from realign_root will be realigned,
885  * so if your string contains other values you will need to deal with
886  * those somehow yourself. It is OK if realign_root is the same
887  * reader as the reader parameter, though if you aren't setting the
888  * root it may not be such a good idea.
889  *
890  * @todo DBusTypeReader currently takes "const" versions of the type
891  * and value strings, and this function modifies those strings by
892  * casting away the const, which is of course bad if we want to get
893  * picky. (To be truly clean you'd have an object which contained the
894  * type and value strings and set_basic would be a method on that
895  * object... this would also make DBusTypeReader the same thing as
896  * DBusTypeMark. But since DBusMessage is effectively that object for
897  * D-BUS it doesn't seem worth creating some random object.)
898  *
899  * @param reader reader indicating where to set a new value
900  * @param value address of the value to set
901  * @param realign_root realign from here
902  * @returns #FALSE if not enough memory
903  */
904 dbus_bool_t
905 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
906                              const void           *value,
907                              const DBusTypeReader *realign_root)
908 {
909   int current_type;
910   dbus_bool_t retval;
911
912   retval = FALSE;
913
914   current_type = _dbus_type_reader_get_current_type (reader);
915
916   _dbus_assert (_dbus_type_is_basic (current_type));
917
918   if (!_dbus_type_length_varies (current_type))
919     {
920       reader_set_basic_fixed_length (reader, current_type, value);
921       return TRUE;
922     }
923
924   _dbus_assert (realign_root != NULL);
925
926   /* In the harder case, we have to fix alignment after we insert.
927    * The basic strategy is as follows:
928    *
929    *  - pad a new string to have the same alignment as the
930    *    start of the current basic value
931    *  - write the new basic value
932    *  - copy from the original reader to the new string,
933    *    which will fix the alignment of types following
934    *    the new value
935    *    - this copy has to start at realign_root,
936    *      but not really write anything until it
937    *      passes the value being set
938    *    - as an optimization, we can stop copying
939    *      when the source and dest values are both
940    *      on an 8-boundary, since we know all following
941    *      padding and alignment will be identical
942    *  - copy the new string back to the original
943    *    string, replacing the relevant part of the
944    *    original string
945    */
946
947
948   retval = TRUE;
949
950  out:
951
952   return retval;
953 }
954
955 /*
956  *
957  *
958  *         DBusTypeWriter
959  *
960  *
961  *
962  */
963
964 /**
965  * Initialize a write iterator, which is used to write out values in
966  * serialized D-BUS format. #DBusTypeWriter is a value iterator; it
967  * writes out values. You can't use it to write out only types.
968  *
969  * The type_pos passed in is expected to be inside an already-valid,
970  * though potentially empty, type signature. This means that the byte
971  * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
972  * other valid type. #DBusTypeWriter won't enforce that the signature
973  * is already valid (you can append the nul byte at the end if you
974  * like), but just be aware that you need the nul byte eventually and
975  * #DBusTypeWriter isn't going to write it for you.
976  *
977  * @param writer the writer to init
978  * @param byte_order the byte order to marshal into
979  * @param type_str the string to write typecodes into
980  * @param type_pos where to insert typecodes
981  * @param value_str the string to write values into
982  * @param value_pos where to insert values
983  *
984  */
985 void
986 _dbus_type_writer_init (DBusTypeWriter *writer,
987                         int             byte_order,
988                         DBusString     *type_str,
989                         int             type_pos,
990                         DBusString     *value_str,
991                         int             value_pos)
992 {
993   writer->byte_order = byte_order;
994   writer->type_str = type_str;
995   writer->type_pos = type_pos;
996   writer->value_str = value_str;
997   writer->value_pos = value_pos;
998   writer->container_type = DBUS_TYPE_INVALID;
999   writer->type_pos_is_expectation = FALSE;
1000
1001 #if RECURSIVE_MARSHAL_TRACE
1002   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1003                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1004 #endif
1005 }
1006
1007 static dbus_bool_t
1008 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1009                                            int             type,
1010                                            const void     *value)
1011 {
1012   return _dbus_marshal_write_basic (writer->value_str,
1013                                     writer->value_pos,
1014                                     type,
1015                                     value,
1016                                     writer->byte_order,
1017                                     &writer->value_pos);
1018 }
1019
1020 /* If our parent is an array, things are a little bit complicated.
1021  *
1022  * The parent must have a complete element type, such as
1023  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1024  * unclosed parens, or an "a" with no following type.
1025  *
1026  * To recurse, the only allowed operation is to recurse into the
1027  * first type in the element type. So for "i" you can't recurse, for
1028  * "ai" you can recurse into the array, for "(ii)" you can recurse
1029  * into the struct.
1030  *
1031  * If you recurse into the array for "ai", then you must specify
1032  * "i" for the element type of the array you recurse into.
1033  *
1034  * While inside an array at any level, we need to avoid writing to
1035  * type_str, since the type only appears once for the whole array,
1036  * it does not appear for each array element.
1037  *
1038  * While inside an array type_pos points to the expected next
1039  * typecode, rather than the next place we could write a typecode.
1040  */
1041 static void
1042 writer_recurse_init_and_check (DBusTypeWriter *writer,
1043                                int             container_type,
1044                                DBusTypeWriter *sub)
1045 {
1046   _dbus_type_writer_init (sub,
1047                           writer->byte_order,
1048                           writer->type_str,
1049                           writer->type_pos,
1050                           writer->value_str,
1051                           writer->value_pos);
1052
1053   sub->container_type = container_type;
1054
1055   if (writer->type_pos_is_expectation ||
1056       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
1057     sub->type_pos_is_expectation = TRUE;
1058   else
1059     sub->type_pos_is_expectation = FALSE;
1060
1061 #ifndef DBUS_DISABLE_CHECKS
1062   if (writer->type_pos_is_expectation)
1063     {
1064       int expected;
1065
1066       expected = first_type_in_signature (writer->type_str, writer->type_pos);
1067
1068       if (expected != sub->container_type)
1069         {
1070           _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
1071                       _dbus_type_to_string (sub->container_type),
1072                       _dbus_type_to_string (expected));
1073           _dbus_assert_not_reached ("bad array element or variant content written");
1074         }
1075     }
1076 #endif /* DBUS_DISABLE_CHECKS */
1077
1078 #if RECURSIVE_MARSHAL_TRACE
1079   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
1080                  writer,
1081                  _dbus_type_to_string (writer->container_type),
1082                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1083                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1084   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d\n",
1085                  sub,
1086                  _dbus_type_to_string (sub->container_type),
1087                  sub->type_pos, sub->value_pos,
1088                  sub->type_pos_is_expectation);
1089 #endif
1090 }
1091
1092 static dbus_bool_t
1093 write_or_verify_typecode (DBusTypeWriter *writer,
1094                           int             typecode)
1095 {
1096   /* A subwriter inside an array or variant will have type_pos
1097    * pointing to the expected typecode; a writer not inside an array
1098    * or variant has type_pos pointing to the next place to insert a
1099    * typecode.
1100    */
1101 #if RECURSIVE_MARSHAL_TRACE
1102   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
1103                  writer, writer->type_pos,
1104                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1105 #endif
1106
1107   if (writer->type_pos_is_expectation)
1108     {
1109 #ifndef DBUS_DISABLE_CHECKS
1110       {
1111         int expected;
1112
1113         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1114
1115         if (expected != typecode)
1116           {
1117             _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1118                         _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1119             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1120           }
1121       }
1122 #endif /* DBUS_DISABLE_CHECKS */
1123
1124       /* if immediately inside an array we'd always be appending an element,
1125        * so the expected type doesn't change; if inside a struct or something
1126        * below an array, we need to move through said struct or something.
1127        */
1128       if (writer->container_type != DBUS_TYPE_ARRAY)
1129         writer->type_pos += 1;
1130     }
1131   else
1132     {
1133       if (!_dbus_string_insert_byte (writer->type_str,
1134                                      writer->type_pos,
1135                                      typecode))
1136         return FALSE;
1137
1138       writer->type_pos += 1;
1139     }
1140
1141 #if RECURSIVE_MARSHAL_TRACE
1142   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1143                  writer, writer->type_pos,
1144                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1145 #endif
1146
1147   return TRUE;
1148 }
1149
1150 static dbus_bool_t
1151 writer_recurse_struct (DBusTypeWriter   *writer,
1152                        const DBusString *contained_type,
1153                        int               contained_type_start,
1154                        int               contained_type_len,
1155                        DBusTypeWriter   *sub)
1156 {
1157   /* FIXME right now contained_type is ignored; we could probably
1158    * almost trivially fix the code so if it's present we
1159    * write it out and then set type_pos_is_expectation
1160    */
1161
1162   /* Ensure that we'll be able to add alignment padding and the typecode */
1163   if (!_dbus_string_alloc_space (sub->value_str, 8))
1164     return FALSE;
1165
1166   if (!_dbus_string_alloc_space (sub->type_str, 1))
1167     return FALSE;
1168
1169   if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1170     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1171
1172   if (!_dbus_string_insert_bytes (sub->value_str,
1173                                   sub->value_pos,
1174                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1175                                   '\0'))
1176     _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1177   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1178
1179   return TRUE;
1180 }
1181
1182
1183 static dbus_bool_t
1184 writer_recurse_array (DBusTypeWriter   *writer,
1185                       const DBusString *contained_type,
1186                       int               contained_type_start,
1187                       int               contained_type_len,
1188                       DBusTypeWriter   *sub)
1189 {
1190   dbus_uint32_t value = 0;
1191   int alignment;
1192   int aligned;
1193
1194 #ifndef DBUS_DISABLE_CHECKS
1195   if (writer->container_type == DBUS_TYPE_ARRAY)
1196     {
1197       if (!_dbus_string_equal_substring (contained_type,
1198                                          contained_type_start,
1199                                          contained_type_len,
1200                                          writer->type_str,
1201                                          writer->u.array.element_type_pos + 1))
1202         {
1203           _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1204                       _dbus_string_get_const_data_len (contained_type,
1205                                                        contained_type_start,
1206                                                        contained_type_len));
1207           _dbus_assert_not_reached ("incompatible type for child array");
1208         }
1209     }
1210 #endif /* DBUS_DISABLE_CHECKS */
1211
1212   /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1213    * before array values
1214    */
1215   if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1216     return FALSE;
1217
1218   sub->type_pos += 1; /* move to point to the element type, since type_pos
1219                        * should be the expected type for further writes
1220                        */
1221   sub->u.array.element_type_pos = sub->type_pos;
1222
1223   if (!writer->type_pos_is_expectation)
1224     {
1225       /* sub is a toplevel/outermost array so we need to write the type data */
1226
1227       /* alloc space for array typecode, element signature */
1228       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1229         return FALSE;
1230
1231       if (!_dbus_string_insert_byte (writer->type_str,
1232                                      writer->type_pos,
1233                                      DBUS_TYPE_ARRAY))
1234         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1235
1236       if (!_dbus_string_copy_len (contained_type,
1237                                   contained_type_start, contained_type_len,
1238                                   sub->type_str,
1239                                   sub->u.array.element_type_pos))
1240         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1241     }
1242
1243   /* If the parent is an array, we hold type_pos pointing at the array element type;
1244    * otherwise advance it to reflect the array value we just recursed into
1245    */
1246   if (writer->container_type != DBUS_TYPE_ARRAY)
1247     writer->type_pos += 1 + contained_type_len;
1248   else
1249     _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1250
1251   /* Write the length */
1252   sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1253
1254   if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1255                                                   &value))
1256     _dbus_assert_not_reached ("should not have failed to insert array len");
1257
1258   _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1259
1260   /* Write alignment padding for array elements
1261    * Note that we write the padding *even for empty arrays*
1262    * to avoid wonky special cases
1263    */
1264   alignment = element_type_get_alignment (contained_type, contained_type_start);
1265
1266   aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1267   if (aligned != sub->value_pos)
1268     {
1269       if (!_dbus_string_insert_bytes (sub->value_str,
1270                                       sub->value_pos,
1271                                       aligned - sub->value_pos,
1272                                       '\0'))
1273         _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1274
1275       sub->value_pos = aligned;
1276     }
1277   sub->u.array.start_pos = sub->value_pos;
1278
1279   _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1280   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1281
1282 #if RECURSIVE_MARSHAL_TRACE
1283   _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1284                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0),
1285                  sub->u.array.start_pos, sub->u.array.len_pos);
1286 #endif
1287
1288   return TRUE;
1289 }
1290
1291 /* Variant value will normally have:
1292  *   1 byte signature length not including nul
1293  *   signature typecodes (nul terminated)
1294  *   padding to 8-boundary
1295  *   body according to signature
1296  *
1297  * The signature string can only have a single type
1298  * in it but that type may be complex/recursive.
1299  *
1300  * So a typical variant type with the integer 3 will have these
1301  * octets:
1302  *   0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1303  *
1304  * For an array of 4-byte types stuffed into variants, the padding to
1305  * 8-boundary is only the 1 byte that is required for the 4-boundary
1306  * anyhow for all array elements after the first one. And for single
1307  * variants in isolation, wasting a few bytes is hardly a big deal.
1308  *
1309  * The main world of hurt for writing out a variant is that the type
1310  * string is the same string as the value string. Which means
1311  * inserting to the type string will move the value_pos; and it means
1312  * that inserting to the type string could break type alignment.
1313  *
1314  * This type alignment issue is why the body of the variant is always
1315  * 8-aligned. Then we know that re-8-aligning the start of the body
1316  * will always correctly align the full contents of the variant type.
1317  */
1318 static dbus_bool_t
1319 writer_recurse_variant (DBusTypeWriter   *writer,
1320                         const DBusString *contained_type,
1321                         int               contained_type_start,
1322                         int               contained_type_len,
1323                         DBusTypeWriter   *sub)
1324 {
1325   /* Allocate space for the worst case, which is 1 byte sig
1326    * length, nul byte at end of sig, and 7 bytes padding to
1327    * 8-boundary.
1328    */
1329   if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1330     return FALSE;
1331
1332   /* write VARIANT typecode to the parent's type string */
1333   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1334     return FALSE;
1335
1336   if (!_dbus_string_insert_byte (sub->value_str,
1337                                  sub->value_pos,
1338                                  contained_type_len))
1339     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1340
1341   sub->value_pos += 1;
1342
1343   /* Here we switch over to the expected type sig we're about to write */
1344   sub->type_str = sub->value_str;
1345   sub->type_pos = sub->value_pos;
1346
1347   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
1348                               sub->value_str, sub->value_pos))
1349     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1350
1351   sub->value_pos += contained_type_len;
1352
1353   if (!_dbus_string_insert_byte (sub->value_str,
1354                                  sub->value_pos,
1355                                  DBUS_TYPE_INVALID))
1356     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1357
1358   sub->value_pos += 1;
1359
1360   if (!_dbus_string_insert_bytes (sub->value_str,
1361                                   sub->value_pos,
1362                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1363                                   '\0'))
1364     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1365   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1366
1367   return TRUE;
1368 }
1369
1370 static dbus_bool_t
1371 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
1372                                          int               container_type,
1373                                          const DBusString *contained_type,
1374                                          int               contained_type_start,
1375                                          int               contained_type_len,
1376                                          DBusTypeWriter   *sub)
1377 {
1378   writer_recurse_init_and_check (writer, container_type, sub);
1379
1380   switch (container_type)
1381     {
1382     case DBUS_TYPE_STRUCT:
1383       return writer_recurse_struct (writer,
1384                                     contained_type, contained_type_start, contained_type_len,
1385                                     sub);
1386       break;
1387     case DBUS_TYPE_ARRAY:
1388       return writer_recurse_array (writer,
1389                                    contained_type, contained_type_start, contained_type_len,
1390                                    sub);
1391       break;
1392     case DBUS_TYPE_VARIANT:
1393       return writer_recurse_variant (writer,
1394                                      contained_type, contained_type_start, contained_type_len,
1395                                      sub);
1396       break;
1397     default:
1398       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
1399       return FALSE;
1400       break;
1401     }
1402 }
1403
1404 dbus_bool_t
1405 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
1406                            int               container_type,
1407                            const DBusString *contained_type,
1408                            int               contained_type_start,
1409                            DBusTypeWriter   *sub)
1410 {
1411   int contained_type_len;
1412
1413   if (contained_type)
1414     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
1415   else
1416     contained_type_len = 0;
1417
1418   return _dbus_type_writer_recurse_contained_len (writer, container_type,
1419                                                   contained_type,
1420                                                   contained_type_start,
1421                                                   contained_type_len,
1422                                                   sub);
1423 }
1424
1425 dbus_bool_t
1426 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1427                              DBusTypeWriter *sub)
1428 {
1429   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1430
1431   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1432   _dbus_assert (!writer->type_pos_is_expectation ||
1433                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1434
1435 #if RECURSIVE_MARSHAL_TRACE
1436   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1437                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1438                  _dbus_type_to_string (writer->container_type));
1439   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1440                  sub, sub->type_pos, sub->value_pos,
1441                  sub->type_pos_is_expectation,
1442                  _dbus_type_to_string (sub->container_type));
1443 #endif
1444
1445   if (sub->container_type == DBUS_TYPE_STRUCT)
1446     {
1447       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1448         return FALSE;
1449     }
1450   else if (sub->container_type == DBUS_TYPE_ARRAY)
1451     {
1452       dbus_uint32_t len;
1453
1454       /* Set the array length */
1455       len = sub->value_pos - sub->u.array.start_pos;
1456       _dbus_marshal_set_uint32 (sub->value_str,
1457                                 sub->u.array.len_pos,
1458                                 len,
1459                                 sub->byte_order);
1460 #if RECURSIVE_MARSHAL_TRACE
1461       _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
1462                      len, sub->u.array.len_pos);
1463 #endif
1464     }
1465
1466   /* Now get type_pos right for the parent writer. Here are the cases:
1467    *
1468    * Cases !writer->type_pos_is_expectation:
1469    *   (in these cases we want to update to the new insertion point)
1470    *
1471    * - if we recursed into a STRUCT then we didn't know in advance
1472    *   what the types in the struct would be; so we have to fill in
1473    *   that information now.
1474    *       writer->type_pos = sub->type_pos
1475    *
1476    * - if we recursed into anything else, we knew the full array
1477    *   type, or knew the single typecode marking VARIANT, so
1478    *   writer->type_pos is already correct.
1479    *       writer->type_pos should remain as-is
1480    *
1481    * - note that the parent is never an ARRAY or VARIANT, if it were
1482    *   then type_pos_is_expectation would be TRUE. The parent
1483    *   is thus known to be a toplevel or STRUCT.
1484    *
1485    * Cases where writer->type_pos_is_expectation:
1486    *   (in these cases we want to update to next expected type to write)
1487    *
1488    * - we recursed from STRUCT into STRUCT and we didn't increment
1489    *   type_pos in the parent just to stay consistent with the
1490    *   !writer->type_pos_is_expectation case (though we could
1491    *   special-case this in recurse_struct instead if we wanted)
1492    *       writer->type_pos = sub->type_pos
1493    *
1494    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1495    *   for parent should have been incremented already
1496    *       writer->type_pos should remain as-is
1497    *
1498    * - we recursed from ARRAY into a sub-element, so type_pos in the
1499    *   parent is the element type and should remain the element type
1500    *   for the benefit of the next child element
1501    *       writer->type_pos should remain as-is
1502    *
1503    * - we recursed from VARIANT into its value, so type_pos in the
1504    *   parent makes no difference since there's only one value
1505    *   and we just finished writing it and won't use type_pos again
1506    *       writer->type_pos should remain as-is
1507    */
1508   if (sub->container_type == DBUS_TYPE_STRUCT &&
1509       (writer->container_type == DBUS_TYPE_STRUCT ||
1510        writer->container_type == DBUS_TYPE_INVALID))
1511     {
1512       /* Advance the parent to the next struct field */
1513       writer->type_pos = sub->type_pos;
1514     }
1515
1516   writer->value_pos = sub->value_pos;
1517
1518 #if RECURSIVE_MARSHAL_TRACE
1519   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1520                  writer, writer->type_pos, writer->value_pos,
1521                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1522 #endif
1523
1524   return TRUE;
1525 }
1526
1527 dbus_bool_t
1528 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1529                                int             type,
1530                                const void     *value)
1531 {
1532   dbus_bool_t retval;
1533
1534   /* First ensure that our type realloc will succeed */
1535   if (!_dbus_string_alloc_space (writer->type_str, 1))
1536     return FALSE;
1537
1538   retval = FALSE;
1539
1540   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1541     goto out;
1542
1543   if (!write_or_verify_typecode (writer, type))
1544     _dbus_assert_not_reached ("failed to write typecode after prealloc");
1545
1546   retval = TRUE;
1547
1548  out:
1549 #if RECURSIVE_MARSHAL_TRACE
1550   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1551                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1552 #endif
1553
1554   return retval;
1555 }
1556
1557 dbus_bool_t
1558 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1559                                int             type,
1560                                const void     *array,
1561                                int             array_len)
1562 {
1563
1564
1565 }
1566
1567 /**
1568  * Iterate through all values in the given reader,
1569  * writing a copy of each value to the writer.
1570  * The reader will be moved forward to its end position.
1571  *
1572  * @param writer the writer to copy to
1573  * @param reader the reader to copy from
1574  */
1575 dbus_bool_t
1576 _dbus_type_writer_write_reader (DBusTypeWriter *writer,
1577                                 DBusTypeReader *reader)
1578 {
1579   DBusTypeWriter orig;
1580   int orig_type_len;
1581   int orig_value_len;
1582   int new_bytes;
1583   int current_type;
1584
1585   orig = *writer;
1586   orig_type_len = _dbus_string_get_length (writer->type_str);
1587   orig_value_len = _dbus_string_get_length (writer->value_str);
1588
1589   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
1590     {
1591       if (_dbus_type_is_container (current_type))
1592         {
1593           DBusTypeReader subreader;
1594           DBusTypeWriter subwriter;
1595           const DBusString *sig_str;
1596           int sig_start;
1597           int sig_len;
1598
1599           _dbus_type_reader_recurse (reader, &subreader);
1600
1601           _dbus_type_reader_get_signature (&subreader, &sig_str,
1602                                            &sig_start, &sig_len);
1603
1604           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
1605                                                         sig_str, sig_start, sig_len,
1606                                                         &subwriter))
1607             goto oom;
1608
1609           if (!_dbus_type_writer_write_reader (&subwriter, &subreader))
1610             goto oom;
1611
1612           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
1613             goto oom;
1614         }
1615       else
1616         {
1617           DBusBasicValue val;
1618
1619           _dbus_assert (_dbus_type_is_basic (current_type));
1620           
1621           _dbus_type_reader_read_basic (reader, &val);
1622           
1623           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
1624             goto oom;
1625         }
1626
1627       _dbus_type_reader_next (reader);
1628     }
1629
1630   return TRUE;
1631
1632  oom:
1633   if (!writer->type_pos_is_expectation)
1634     {
1635       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
1636       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
1637     }
1638   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
1639   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
1640
1641   *writer = orig;
1642
1643   return FALSE;
1644 }
1645
1646 /** @} */ /* end of DBusMarshal group */
1647
1648 #ifdef DBUS_BUILD_TESTS
1649 #include "dbus-test.h"
1650 #include "dbus-list.h"
1651 #include <stdio.h>
1652 #include <stdlib.h>
1653
1654 /* Whether to do the OOM stuff */
1655 #define TEST_OOM_HANDLING 0
1656 /* We do start offset 0 through 9, to get various alignment cases. Still this
1657  * obviously makes the test suite run 10x as slow.
1658  */
1659 #define MAX_INITIAL_OFFSET 9
1660 /* Largest iteration count to test copying with. i.e. we only test copying with
1661  * some of the smaller data sets.
1662  */
1663 #define MAX_ITERATIONS_TO_TEST_COPYING 100
1664
1665 typedef struct
1666 {
1667   int byte_order;
1668   int initial_offset;
1669   DBusString signature;
1670   DBusString body;
1671 } DataBlock;
1672
1673 typedef struct
1674 {
1675   int saved_sig_len;
1676   int saved_body_len;
1677 } DataBlockState;
1678
1679 #define N_FENCE_BYTES 5
1680 #define FENCE_BYTES_STR "abcde"
1681 #define INITIAL_PADDING_BYTE '\0'
1682
1683 static dbus_bool_t
1684 data_block_init (DataBlock *block,
1685                  int        byte_order,
1686                  int        initial_offset)
1687 {
1688   if (!_dbus_string_init (&block->signature))
1689     return FALSE;
1690
1691   if (!_dbus_string_init (&block->body))
1692     {
1693       _dbus_string_free (&block->signature);
1694       return FALSE;
1695     }
1696
1697   if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
1698                                   INITIAL_PADDING_BYTE) ||
1699       !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
1700                                   INITIAL_PADDING_BYTE) ||
1701       !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
1702       !_dbus_string_append (&block->body, FENCE_BYTES_STR))
1703     {
1704       _dbus_string_free (&block->signature);
1705       _dbus_string_free (&block->body);
1706       return FALSE;
1707     }
1708
1709   block->byte_order = byte_order;
1710   block->initial_offset = initial_offset;
1711
1712   return TRUE;
1713 }
1714
1715 static void
1716 data_block_save (DataBlock      *block,
1717                  DataBlockState *state)
1718 {
1719   state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
1720   state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
1721 }
1722
1723 static void
1724 data_block_restore (DataBlock      *block,
1725                     DataBlockState *state)
1726 {
1727   _dbus_string_delete (&block->signature,
1728                        state->saved_sig_len,
1729                        _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
1730   _dbus_string_delete (&block->body,
1731                        state->saved_body_len,
1732                        _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
1733 }
1734
1735 static void
1736 data_block_verify (DataBlock *block)
1737 {
1738   if (!_dbus_string_ends_with_c_str (&block->signature,
1739                                      FENCE_BYTES_STR))
1740     {
1741       int offset;
1742
1743       offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
1744       if (offset < 0)
1745         offset = 0;
1746
1747       _dbus_verbose_bytes_of_string (&block->signature,
1748                                      offset,
1749                                      _dbus_string_get_length (&block->signature) - offset);
1750       _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
1751     }
1752   if (!_dbus_string_ends_with_c_str (&block->body,
1753                                      FENCE_BYTES_STR))
1754     {
1755       int offset;
1756
1757       offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
1758       if (offset < 0)
1759         offset = 0;
1760
1761       _dbus_verbose_bytes_of_string (&block->body,
1762                                      offset,
1763                                      _dbus_string_get_length (&block->body) - offset);
1764       _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
1765     }
1766
1767   _dbus_assert (_dbus_string_validate_nul (&block->signature,
1768                                            0, block->initial_offset));
1769   _dbus_assert (_dbus_string_validate_nul (&block->body,
1770                                            0, block->initial_offset));
1771 }
1772
1773 static void
1774 data_block_free (DataBlock *block)
1775 {
1776   data_block_verify (block);
1777
1778   _dbus_string_free (&block->signature);
1779   _dbus_string_free (&block->body);
1780 }
1781
1782 static void
1783 data_block_reset (DataBlock *block)
1784 {
1785   data_block_verify (block);
1786
1787   _dbus_string_delete (&block->signature,
1788                        block->initial_offset,
1789                        _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
1790   _dbus_string_delete (&block->body,
1791                        block->initial_offset,
1792                        _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
1793
1794   data_block_verify (block);
1795 }
1796
1797 static void
1798 data_block_init_reader_writer (DataBlock      *block,
1799                                DBusTypeReader *reader,
1800                                DBusTypeWriter *writer)
1801 {
1802   if (reader)
1803     _dbus_type_reader_init (reader,
1804                             block->byte_order,
1805                             &block->signature,
1806                             block->initial_offset,
1807                             &block->body,
1808                             block->initial_offset);
1809
1810   if (writer)
1811     _dbus_type_writer_init (writer,
1812                             block->byte_order,
1813                             &block->signature,
1814                             _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
1815                             &block->body,
1816                             _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
1817 }
1818
1819 static void
1820 real_check_expected_type (DBusTypeReader *reader,
1821                           int             expected,
1822                           const char     *funcname,
1823                           int             line)
1824 {
1825   int t;
1826
1827   t = _dbus_type_reader_get_current_type (reader);
1828
1829   if (t != expected)
1830     {
1831       _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1832                   _dbus_type_to_string (t),
1833                   _dbus_type_to_string (expected),
1834                   funcname, line);
1835
1836       exit (1);
1837     }
1838 }
1839
1840 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1841
1842 #define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \
1843  {                                                                                      \
1844     _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \
1845                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1846     _dbus_assert_not_reached ("test failed");                                           \
1847  }                                                                                      \
1848 } while (0)
1849
1850 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \
1851  {                                                                                      \
1852     _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \
1853                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1854     _dbus_assert_not_reached ("test failed");                                           \
1855  }                                                                                      \
1856  check_expected_type (reader, DBUS_TYPE_INVALID);                                       \
1857 } while (0)
1858
1859 typedef struct TestTypeNode               TestTypeNode;
1860 typedef struct TestTypeNodeClass          TestTypeNodeClass;
1861 typedef struct TestTypeNodeContainer      TestTypeNodeContainer;
1862 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1863
1864 struct TestTypeNode
1865 {
1866   const TestTypeNodeClass *klass;
1867 };
1868
1869 struct TestTypeNodeContainer
1870 {
1871   TestTypeNode base;
1872   DBusList    *children;
1873 };
1874
1875 struct TestTypeNodeClass
1876 {
1877   int typecode;
1878
1879   int instance_size;
1880
1881   int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
1882
1883   dbus_bool_t   (* construct)     (TestTypeNode   *node);
1884   void          (* destroy)       (TestTypeNode   *node);
1885
1886   dbus_bool_t (* write_value)     (TestTypeNode   *node,
1887                                    DataBlock      *block,
1888                                    DBusTypeWriter *writer,
1889                                    int             seed);
1890   dbus_bool_t (* read_value)      (TestTypeNode   *node,
1891                                    DataBlock      *block,
1892                                    DBusTypeReader *reader,
1893                                    int             seed);
1894   dbus_bool_t (* build_signature) (TestTypeNode   *node,
1895                                    DBusString     *str);
1896 };
1897
1898 struct TestTypeNodeContainerClass
1899 {
1900   TestTypeNodeClass base;
1901 };
1902
1903 static dbus_bool_t int32_write_value       (TestTypeNode   *node,
1904                                             DataBlock      *block,
1905                                             DBusTypeWriter *writer,
1906                                             int             seed);
1907 static dbus_bool_t int32_read_value        (TestTypeNode   *node,
1908                                             DataBlock      *block,
1909                                             DBusTypeReader *reader,
1910                                             int             seed);
1911 static dbus_bool_t int64_write_value       (TestTypeNode   *node,
1912                                             DataBlock      *block,
1913                                             DBusTypeWriter *writer,
1914                                             int             seed);
1915 static dbus_bool_t int64_read_value        (TestTypeNode   *node,
1916                                             DataBlock      *block,
1917                                             DBusTypeReader *reader,
1918                                             int             seed);
1919 static dbus_bool_t string_write_value      (TestTypeNode   *node,
1920                                             DataBlock      *block,
1921                                             DBusTypeWriter *writer,
1922                                             int             seed);
1923 static dbus_bool_t string_read_value       (TestTypeNode   *node,
1924                                             DataBlock      *block,
1925                                             DBusTypeReader *reader,
1926                                             int             seed);
1927 static dbus_bool_t bool_read_value         (TestTypeNode   *node,
1928                                             DataBlock      *block,
1929                                             DBusTypeReader *reader,
1930                                             int             seed);
1931 static dbus_bool_t bool_write_value        (TestTypeNode   *node,
1932                                             DataBlock      *block,
1933                                             DBusTypeWriter *writer,
1934                                             int             seed);
1935 static dbus_bool_t byte_read_value         (TestTypeNode   *node,
1936                                             DataBlock      *block,
1937                                             DBusTypeReader *reader,
1938                                             int             seed);
1939 static dbus_bool_t byte_write_value        (TestTypeNode   *node,
1940                                             DataBlock      *block,
1941                                             DBusTypeWriter *writer,
1942                                             int             seed);
1943 static dbus_bool_t double_read_value       (TestTypeNode   *node,
1944                                             DataBlock      *block,
1945                                             DBusTypeReader *reader,
1946                                             int             seed);
1947 static dbus_bool_t double_write_value      (TestTypeNode   *node,
1948                                             DataBlock      *block,
1949                                             DBusTypeWriter *writer,
1950                                             int             seed);
1951 static dbus_bool_t object_path_read_value  (TestTypeNode   *node,
1952                                             DataBlock      *block,
1953                                             DBusTypeReader *reader,
1954                                             int             seed);
1955 static dbus_bool_t object_path_write_value (TestTypeNode   *node,
1956                                             DataBlock      *block,
1957                                             DBusTypeWriter *writer,
1958                                             int             seed);
1959 static dbus_bool_t signature_read_value    (TestTypeNode   *node,
1960                                             DataBlock      *block,
1961                                             DBusTypeReader *reader,
1962                                             int             seed);
1963 static dbus_bool_t signature_write_value   (TestTypeNode   *node,
1964                                             DataBlock      *block,
1965                                             DBusTypeWriter *writer,
1966                                             int             seed);
1967 static dbus_bool_t struct_write_value      (TestTypeNode   *node,
1968                                             DataBlock      *block,
1969                                             DBusTypeWriter *writer,
1970                                             int             seed);
1971 static dbus_bool_t struct_read_value       (TestTypeNode   *node,
1972                                             DataBlock      *block,
1973                                             DBusTypeReader *reader,
1974                                             int             seed);
1975 static dbus_bool_t struct_build_signature  (TestTypeNode   *node,
1976                                             DBusString     *str);
1977 static dbus_bool_t array_write_value       (TestTypeNode   *node,
1978                                             DataBlock      *block,
1979                                             DBusTypeWriter *writer,
1980                                             int             seed);
1981 static dbus_bool_t array_read_value        (TestTypeNode   *node,
1982                                             DataBlock      *block,
1983                                             DBusTypeReader *reader,
1984                                             int             seed);
1985 static dbus_bool_t array_build_signature   (TestTypeNode   *node,
1986                                             DBusString     *str);
1987 static dbus_bool_t variant_write_value     (TestTypeNode   *node,
1988                                             DataBlock      *block,
1989                                             DBusTypeWriter *writer,
1990                                             int             seed);
1991 static dbus_bool_t variant_read_value      (TestTypeNode   *node,
1992                                             DataBlock      *block,
1993                                             DBusTypeReader *reader,
1994                                             int             seed);
1995 static void        container_destroy       (TestTypeNode   *node);
1996
1997
1998 static const TestTypeNodeClass int32_class = {
1999   DBUS_TYPE_INT32,
2000   sizeof (TestTypeNode),
2001   0,
2002   NULL,
2003   NULL,
2004   int32_write_value,
2005   int32_read_value,
2006   NULL
2007 };
2008
2009 static const TestTypeNodeClass uint32_class = {
2010   DBUS_TYPE_UINT32,
2011   sizeof (TestTypeNode),
2012   0,
2013   NULL,
2014   NULL,
2015   int32_write_value, /* recycle from int32 */
2016   int32_read_value,  /* recycle from int32 */
2017   NULL
2018 };
2019
2020 static const TestTypeNodeClass int64_class = {
2021   DBUS_TYPE_INT64,
2022   sizeof (TestTypeNode),
2023   0,
2024   NULL,
2025   NULL,
2026   int64_write_value,
2027   int64_read_value,
2028   NULL
2029 };
2030
2031 static const TestTypeNodeClass uint64_class = {
2032   DBUS_TYPE_UINT64,
2033   sizeof (TestTypeNode),
2034   0,
2035   NULL,
2036   NULL,
2037   int64_write_value, /* recycle from int64 */
2038   int64_read_value,  /* recycle from int64 */
2039   NULL
2040 };
2041
2042 static const TestTypeNodeClass string_0_class = {
2043   DBUS_TYPE_STRING,
2044   sizeof (TestTypeNode),
2045   0, /* string length */
2046   NULL,
2047   NULL,
2048   string_write_value,
2049   string_read_value,
2050   NULL
2051 };
2052
2053 static const TestTypeNodeClass string_1_class = {
2054   DBUS_TYPE_STRING,
2055   sizeof (TestTypeNode),
2056   1, /* string length */
2057   NULL,
2058   NULL,
2059   string_write_value,
2060   string_read_value,
2061   NULL
2062 };
2063
2064 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
2065 static const TestTypeNodeClass string_3_class = {
2066   DBUS_TYPE_STRING,
2067   sizeof (TestTypeNode),
2068   3, /* string length */
2069   NULL,
2070   NULL,
2071   string_write_value,
2072   string_read_value,
2073   NULL
2074 };
2075
2076 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
2077 static const TestTypeNodeClass string_8_class = {
2078   DBUS_TYPE_STRING,
2079   sizeof (TestTypeNode),
2080   8, /* string length */
2081   NULL,
2082   NULL,
2083   string_write_value,
2084   string_read_value,
2085   NULL
2086 };
2087
2088 static const TestTypeNodeClass bool_class = {
2089   DBUS_TYPE_BOOLEAN,
2090   sizeof (TestTypeNode),
2091   0,
2092   NULL,
2093   NULL,
2094   bool_write_value,
2095   bool_read_value,
2096   NULL
2097 };
2098
2099 static const TestTypeNodeClass byte_class = {
2100   DBUS_TYPE_BYTE,
2101   sizeof (TestTypeNode),
2102   0,
2103   NULL,
2104   NULL,
2105   byte_write_value,
2106   byte_read_value,
2107   NULL
2108 };
2109
2110 static const TestTypeNodeClass double_class = {
2111   DBUS_TYPE_DOUBLE,
2112   sizeof (TestTypeNode),
2113   0,
2114   NULL,
2115   NULL,
2116   double_write_value,
2117   double_read_value,
2118   NULL
2119 };
2120
2121 static const TestTypeNodeClass object_path_class = {
2122   DBUS_TYPE_OBJECT_PATH,
2123   sizeof (TestTypeNode),
2124   0,
2125   NULL,
2126   NULL,
2127   object_path_write_value,
2128   object_path_read_value,
2129   NULL
2130 };
2131
2132 static const TestTypeNodeClass signature_class = {
2133   DBUS_TYPE_SIGNATURE,
2134   sizeof (TestTypeNode),
2135   0,
2136   NULL,
2137   NULL,
2138   signature_write_value,
2139   signature_read_value,
2140   NULL
2141 };
2142
2143 static const TestTypeNodeClass struct_1_class = {
2144   DBUS_TYPE_STRUCT,
2145   sizeof (TestTypeNodeContainer),
2146   1, /* number of times children appear as fields */
2147   NULL,
2148   container_destroy,
2149   struct_write_value,
2150   struct_read_value,
2151   struct_build_signature
2152 };
2153
2154 static const TestTypeNodeClass struct_2_class = {
2155   DBUS_TYPE_STRUCT,
2156   sizeof (TestTypeNodeContainer),
2157   2, /* number of times children appear as fields */
2158   NULL,
2159   container_destroy,
2160   struct_write_value,
2161   struct_read_value,
2162   struct_build_signature
2163 };
2164
2165 static const TestTypeNodeClass array_0_class = {
2166   DBUS_TYPE_ARRAY,
2167   sizeof (TestTypeNodeContainer),
2168   0, /* number of array elements */
2169   NULL,
2170   container_destroy,
2171   array_write_value,
2172   array_read_value,
2173   array_build_signature
2174 };
2175
2176 static const TestTypeNodeClass array_1_class = {
2177   DBUS_TYPE_ARRAY,
2178   sizeof (TestTypeNodeContainer),
2179   1, /* number of array elements */
2180   NULL,
2181   container_destroy,
2182   array_write_value,
2183   array_read_value,
2184   array_build_signature
2185 };
2186
2187 static const TestTypeNodeClass array_2_class = {
2188   DBUS_TYPE_ARRAY,
2189   sizeof (TestTypeNodeContainer),
2190   2, /* number of array elements */
2191   NULL,
2192   container_destroy,
2193   array_write_value,
2194   array_read_value,
2195   array_build_signature
2196 };
2197
2198 static const TestTypeNodeClass array_9_class = {
2199   DBUS_TYPE_ARRAY,
2200   sizeof (TestTypeNodeContainer),
2201   9, /* number of array elements */
2202   NULL,
2203   container_destroy,
2204   array_write_value,
2205   array_read_value,
2206   array_build_signature
2207 };
2208
2209 static const TestTypeNodeClass variant_class = {
2210   DBUS_TYPE_VARIANT,
2211   sizeof (TestTypeNodeContainer),
2212   0,
2213   NULL,
2214   container_destroy,
2215   variant_write_value,
2216   variant_read_value,
2217   NULL
2218 };
2219
2220 static const TestTypeNodeClass* const
2221 basic_nodes[] = {
2222   &int32_class,
2223   &uint32_class,
2224   &int64_class,
2225   &uint64_class,
2226   &bool_class,
2227   &byte_class,
2228   &double_class,
2229   &string_0_class,
2230   &string_1_class,
2231   &string_3_class,
2232   &string_8_class,
2233   &object_path_class,
2234   &signature_class
2235 };
2236 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2237
2238 static const TestTypeNodeClass* const
2239 container_nodes[] = {
2240   &struct_1_class,
2241   &array_1_class,
2242   &struct_2_class,
2243   &array_0_class,
2244   &array_2_class,
2245   &variant_class
2246   /* array_9_class is omitted on purpose, it's too slow;
2247    * we only use it in one hardcoded test below
2248    */
2249 };
2250 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2251
2252 static TestTypeNode*
2253 node_new (const TestTypeNodeClass *klass)
2254 {
2255   TestTypeNode *node;
2256
2257   node = dbus_malloc0 (klass->instance_size);
2258   if (node == NULL)
2259     return NULL;
2260
2261   node->klass = klass;
2262
2263   if (klass->construct)
2264     {
2265       if (!(* klass->construct) (node))
2266         {
2267           dbus_free (node);
2268           return FALSE;
2269         }
2270     }
2271
2272   return node;
2273 }
2274
2275 static void
2276 node_destroy (TestTypeNode *node)
2277 {
2278   if (node->klass->destroy)
2279     (* node->klass->destroy) (node);
2280   dbus_free (node);
2281 }
2282
2283 static dbus_bool_t
2284 node_write_value (TestTypeNode   *node,
2285                   DataBlock      *block,
2286                   DBusTypeWriter *writer,
2287                   int             seed)
2288 {
2289   dbus_bool_t retval;
2290
2291   retval = (* node->klass->write_value) (node, block, writer, seed);
2292
2293 #if 0
2294   /* Handy to see where things break, but too expensive to do all the time */
2295   data_block_verify (block);
2296 #endif
2297
2298   return retval;
2299 }
2300
2301 static dbus_bool_t
2302 node_read_value (TestTypeNode   *node,
2303                  DataBlock      *block,
2304                  DBusTypeReader *reader,
2305                  int             seed)
2306 {
2307   DBusTypeMark mark;
2308   DBusTypeReader restored;
2309
2310   _dbus_type_reader_save_mark (reader, &mark);
2311
2312   if (!(* node->klass->read_value) (node, block, reader, seed))
2313     return FALSE;
2314
2315   _dbus_type_reader_init_from_mark (&restored,
2316                                     reader->byte_order, /* a bit of a cheat,
2317                                                          * since we didn't bother
2318                                                          * to store this in DataBlock
2319                                                          */
2320                                     &block->signature,
2321                                     &block->body,
2322                                     &mark);
2323
2324   if (!(* node->klass->read_value) (node, block, &restored, seed))
2325     return FALSE;
2326
2327   return TRUE;
2328 }
2329
2330 static dbus_bool_t
2331 node_build_signature (TestTypeNode *node,
2332                       DBusString   *str)
2333 {
2334   if (node->klass->build_signature)
2335     return (* node->klass->build_signature) (node, str);
2336   else
2337     return _dbus_string_append_byte (str, node->klass->typecode);
2338 }
2339
2340 static dbus_bool_t
2341 node_append_child (TestTypeNode *node,
2342                    TestTypeNode *child)
2343 {
2344   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2345
2346   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2347
2348   if (!_dbus_list_append (&container->children, child))
2349     _dbus_assert_not_reached ("no memory"); /* we never check the return value on node_append_child anyhow - it's run from outside the malloc-failure test code */
2350
2351   return TRUE;
2352 }
2353
2354 static dbus_bool_t
2355 run_test_copy (DataBlock *src)
2356 {
2357   DataBlock dest;
2358   dbus_bool_t retval;
2359   DBusTypeReader reader;
2360   DBusTypeWriter writer;
2361
2362   retval = FALSE;
2363
2364   if (!data_block_init (&dest, src->byte_order, src->initial_offset))
2365     return FALSE;
2366
2367   data_block_init_reader_writer (src, &reader, NULL);
2368   data_block_init_reader_writer (&dest, NULL, &writer);
2369
2370   /* DBusTypeWriter assumes it's writing into an existing signature,
2371    * so doesn't add nul on its own. We have to do that.
2372    */
2373   if (!_dbus_string_insert_byte (&dest.signature,
2374                                  dest.initial_offset, '\0'))
2375     goto out;
2376
2377   if (!_dbus_type_writer_write_reader (&writer, &reader))
2378     goto out;
2379
2380   /* Data blocks should now be identical */
2381   if (!_dbus_string_equal (&src->signature, &dest.signature))
2382     {
2383       _dbus_verbose ("SOURCE\n");
2384       _dbus_verbose_bytes_of_string (&src->signature, 0,
2385                                      _dbus_string_get_length (&src->signature));
2386       _dbus_verbose ("DEST\n");
2387       _dbus_verbose_bytes_of_string (&dest.signature, 0,
2388                                      _dbus_string_get_length (&dest.signature));
2389       _dbus_assert_not_reached ("signatures did not match");
2390     }
2391
2392   if (!_dbus_string_equal (&src->body, &dest.body))
2393     {
2394       _dbus_verbose ("SOURCE\n");
2395       _dbus_verbose_bytes_of_string (&src->body, 0,
2396                                      _dbus_string_get_length (&src->body));
2397       _dbus_verbose ("DEST\n");
2398       _dbus_verbose_bytes_of_string (&dest.body, 0,
2399                                      _dbus_string_get_length (&dest.body));
2400       _dbus_assert_not_reached ("bodies did not match");
2401     }
2402
2403   retval = TRUE;
2404
2405  out:
2406
2407   data_block_free (&dest);
2408
2409   return retval;
2410 }
2411
2412 static int n_iterations_completed_total = 0;
2413 static int n_iterations_completed_this_test = 0;
2414 static int n_iterations_expected_this_test = 0;
2415
2416 typedef struct
2417 {
2418   const DBusString   *signature;
2419   DataBlock          *block;
2420   int                 type_offset;
2421   TestTypeNode      **nodes;
2422   int                 n_nodes;
2423 } NodeIterationData;
2424
2425 static dbus_bool_t
2426 run_test_nodes_iteration (void *data)
2427 {
2428   NodeIterationData *nid = data;
2429   DBusTypeReader reader;
2430   DBusTypeWriter writer;
2431   int i;
2432   dbus_bool_t retval;
2433
2434   /* Stuff to do:
2435    * 1. write the value
2436    * 2. strcmp-compare with the signature we built
2437    * 3. read the value
2438    * 4. type-iterate the signature and the value and see if they are the same type-wise
2439    */
2440   retval = FALSE;
2441
2442   data_block_init_reader_writer (nid->block,
2443                                  &reader, &writer);
2444
2445   /* DBusTypeWriter assumes it's writing into an existing signature,
2446    * so doesn't add nul on its own. We have to do that.
2447    */
2448   if (!_dbus_string_insert_byte (&nid->block->signature,
2449                                  nid->type_offset, '\0'))
2450     goto out;
2451
2452   i = 0;
2453   while (i < nid->n_nodes)
2454     {
2455       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2456         goto out;
2457
2458       ++i;
2459     }
2460
2461   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2462                                      &nid->block->signature, nid->type_offset))
2463     {
2464       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2465                   _dbus_string_get_const_data (nid->signature),
2466                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2467                   nid->type_offset);
2468       _dbus_assert_not_reached ("wrong signature");
2469     }
2470
2471   i = 0;
2472   while (i < nid->n_nodes)
2473     {
2474       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
2475         goto out;
2476
2477       if (i + 1 == nid->n_nodes)
2478         NEXT_EXPECTING_FALSE (&reader);
2479       else
2480         NEXT_EXPECTING_TRUE (&reader);
2481
2482       ++i;
2483     }
2484
2485   if (n_iterations_expected_this_test <= MAX_ITERATIONS_TO_TEST_COPYING)
2486     run_test_copy (nid->block);
2487
2488   /* FIXME type-iterate both signature and value and compare the resulting
2489    * tree to the node tree perhaps
2490    */
2491
2492   retval = TRUE;
2493
2494  out:
2495
2496   data_block_reset (nid->block);
2497
2498   return retval;
2499 }
2500
2501 static void
2502 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
2503                                      int               n_nodes,
2504                                      const DBusString *signature,
2505                                      int               byte_order,
2506                                      int               initial_offset)
2507 {
2508   DataBlock block;
2509   NodeIterationData nid;
2510
2511   if (!data_block_init (&block, byte_order, initial_offset))
2512     _dbus_assert_not_reached ("no memory");
2513
2514   nid.signature = signature;
2515   nid.block = &block;
2516   nid.type_offset = initial_offset;
2517   nid.nodes = nodes;
2518   nid.n_nodes = n_nodes;
2519
2520 #if TEST_OOM_HANDLING
2521   _dbus_test_oom_handling ("running test node",
2522                            run_test_nodes_iteration,
2523                            &nid);
2524 #else
2525   if (!run_test_nodes_iteration (&nid))
2526     _dbus_assert_not_reached ("no memory");
2527 #endif
2528
2529   data_block_free (&block);
2530 }
2531
2532 static void
2533 run_test_nodes (TestTypeNode **nodes,
2534                 int            n_nodes)
2535 {
2536   int i;
2537   DBusString signature;
2538
2539   if (!_dbus_string_init (&signature))
2540     _dbus_assert_not_reached ("no memory");
2541
2542   i = 0;
2543   while (i < n_nodes)
2544     {
2545       if (! node_build_signature (nodes[i], &signature))
2546         _dbus_assert_not_reached ("no memory");
2547
2548       ++i;
2549     }
2550
2551   _dbus_verbose (">>> test nodes with signature '%s'\n",
2552                  _dbus_string_get_const_data (&signature));
2553
2554   i = 0;
2555   while (i <= MAX_INITIAL_OFFSET)
2556     {
2557       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2558                                            DBUS_LITTLE_ENDIAN, i);
2559       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2560                                            DBUS_BIG_ENDIAN, i);
2561
2562       ++i;
2563     }
2564
2565   n_iterations_completed_this_test += 1;
2566   n_iterations_completed_total += 1;
2567
2568   if (n_iterations_completed_this_test == n_iterations_expected_this_test)
2569     {
2570       fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
2571                n_iterations_completed_this_test,
2572                n_iterations_completed_total);
2573     }
2574   /* this happens to turn out well with mod == 1 */
2575   else if ((n_iterations_completed_this_test %
2576             (int)(n_iterations_expected_this_test / 10.0)) == 1)
2577     {
2578       fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
2579     }
2580
2581   _dbus_string_free (&signature);
2582 }
2583
2584 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
2585
2586 static TestTypeNode*
2587 value_generator (int *ip)
2588 {
2589   int i = *ip;
2590   const TestTypeNodeClass *child_klass;
2591   const TestTypeNodeClass *container_klass;
2592   TestTypeNode *child;
2593   TestTypeNode *node;
2594
2595   _dbus_assert (i <= N_VALUES);
2596
2597   if (i == N_VALUES)
2598     {
2599       return NULL;
2600     }
2601   else if (i < N_BASICS)
2602     {
2603       node = node_new (basic_nodes[i]);
2604     }
2605   else
2606     {
2607       /* imagine an array:
2608        * container 0 of basic 0
2609        * container 0 of basic 1
2610        * container 0 of basic 2
2611        * container 1 of basic 0
2612        * container 1 of basic 1
2613        * container 1 of basic 2
2614        */
2615       i -= N_BASICS;
2616
2617       container_klass = container_nodes[i / N_BASICS];
2618       child_klass = basic_nodes[i % N_BASICS];
2619
2620       node = node_new (container_klass);
2621       child = node_new (child_klass);
2622
2623       node_append_child (node, child);
2624     }
2625
2626   *ip += 1; /* increment the generator */
2627
2628   return node;
2629 }
2630
2631 static void
2632 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2633                                       int                      n_nested)
2634 {
2635   TestTypeNode *root;
2636   TestTypeNode *container;
2637   TestTypeNode *child;
2638   int i;
2639
2640   root = node_new (container_klass);
2641   container = root;
2642   for (i = 1; i < n_nested; i++)
2643     {
2644       child = node_new (container_klass);
2645       node_append_child (container, child);
2646       container = child;
2647     }
2648
2649   /* container should now be the most-nested container */
2650
2651   i = 0;
2652   while ((child = value_generator (&i)))
2653     {
2654       node_append_child (container, child);
2655
2656       run_test_nodes (&root, 1);
2657
2658       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2659       node_destroy (child);
2660     }
2661
2662   node_destroy (root);
2663 }
2664
2665 static void
2666 start_next_test (const char *format,
2667                  int         expected)
2668 {
2669   n_iterations_completed_this_test = 0;
2670   n_iterations_expected_this_test = expected;
2671
2672   fprintf (stderr, ">>> >>> ");
2673   fprintf (stderr, format,
2674            n_iterations_expected_this_test);
2675 }
2676
2677 static void
2678 make_and_run_test_nodes (void)
2679 {
2680   int i, j, k, m;
2681
2682   /* We try to do this in order of "complicatedness" so that test
2683    * failures tend to show up in the simplest test case that
2684    * demonstrates the failure.  There are also some tests that run
2685    * more than once for this reason, first while going through simple
2686    * cases, second while going through a broader range of complex
2687    * cases.
2688    */
2689   /* Each basic node. The basic nodes should include:
2690    *
2691    * - each fixed-size type (in such a way that it has different values each time,
2692    *                         so we can tell if we mix two of them up)
2693    * - strings of various lengths
2694    * - object path
2695    * - signature
2696    */
2697   /* Each container node. The container nodes should include:
2698    *
2699    *  struct with 1 and 2 copies of the contained item
2700    *  array with 0, 1, 2 copies of the contained item
2701    *  variant
2702    */
2703   /*  Let a "value" be a basic node, or a container containing a single basic node.
2704    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2705    *  When iterating through all values to make combinations, do the basic types
2706    *  first and the containers second.
2707    */
2708   /* Each item is shown with its number of iterations to complete so
2709    * we can keep a handle on this unit test
2710    */
2711
2712   /* FIXME test just an empty body, no types at all */
2713
2714   start_next_test ("Each value by itself %d iterations\n", N_VALUES);
2715   {
2716     TestTypeNode *node;
2717     i = 0;
2718     while ((node = value_generator (&i)))
2719       {
2720         run_test_nodes (&node, 1);
2721
2722         node_destroy (node);
2723       }
2724   }
2725
2726   start_next_test ("All values in one big toplevel %d iteration\n", 1);
2727   {
2728     TestTypeNode *nodes[N_VALUES];
2729
2730     i = 0;
2731     while ((nodes[i] = value_generator (&i)))
2732       ;
2733
2734     run_test_nodes (nodes, N_VALUES);
2735
2736     for (i = 0; i < N_VALUES; i++)
2737       node_destroy (nodes[i]);
2738   }
2739
2740   start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
2741                    N_VALUES * N_VALUES);
2742   {
2743     TestTypeNode *nodes[2];
2744
2745     i = 0;
2746     while ((nodes[0] = value_generator (&i)))
2747       {
2748         j = 0;
2749         while ((nodes[1] = value_generator (&j)))
2750           {
2751             run_test_nodes (nodes, 2);
2752
2753             node_destroy (nodes[1]);
2754           }
2755
2756         node_destroy (nodes[0]);
2757       }
2758   }
2759
2760   start_next_test ("Each container containing each value %d iterations\n",
2761                    N_CONTAINERS * N_VALUES);
2762   for (i = 0; i < N_CONTAINERS; i++)
2763     {
2764       const TestTypeNodeClass *container_klass = container_nodes[i];
2765
2766       make_and_run_values_inside_container (container_klass, 1);
2767     }
2768
2769   n_iterations_completed_this_test = 0;
2770   n_iterations_expected_this_test = N_CONTAINERS * N_VALUES;
2771   _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2772                  n_iterations_completed_this_test);
2773   for (i = 0; i < N_CONTAINERS; i++)
2774     {
2775       const TestTypeNodeClass *container_klass = container_nodes[i];
2776
2777       make_and_run_values_inside_container (container_klass, 2);
2778     }
2779
2780   start_next_test ("Each container of same container of same container of each value %d iterations\n",
2781                    N_CONTAINERS * N_VALUES);
2782   for (i = 0; i < N_CONTAINERS; i++)
2783     {
2784       const TestTypeNodeClass *container_klass = container_nodes[i];
2785
2786       make_and_run_values_inside_container (container_klass, 3);
2787     }
2788
2789   start_next_test ("Each value,value pair inside a struct %d iterations\n",
2790                    N_VALUES * N_VALUES);
2791   {
2792     TestTypeNode *val1, *val2;
2793     TestTypeNode *node;
2794
2795     node = node_new (&struct_1_class);
2796
2797     i = 0;
2798     while ((val1 = value_generator (&i)))
2799       {
2800         j = 0;
2801         while ((val2 = value_generator (&j)))
2802           {
2803             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2804
2805             node_append_child (node, val1);
2806             node_append_child (node, val2);
2807
2808             run_test_nodes (&node, 1);
2809
2810             _dbus_list_clear (&container->children);
2811             node_destroy (val2);
2812           }
2813         node_destroy (val1);
2814       }
2815     node_destroy (node);
2816   }
2817
2818   start_next_test ("All values in one big struct %d iteration\n",
2819                    1);
2820   {
2821     TestTypeNode *node;
2822     TestTypeNode *child;
2823
2824     node = node_new (&struct_1_class);
2825
2826     i = 0;
2827     while ((child = value_generator (&i)))
2828       node_append_child (node, child);
2829
2830     run_test_nodes (&node, 1);
2831
2832     node_destroy (node);
2833   }
2834
2835   start_next_test ("Each value in a large array %d iterations\n",
2836                    N_VALUES);
2837   {
2838     TestTypeNode *val;
2839     TestTypeNode *node;
2840
2841     node = node_new (&array_9_class);
2842
2843     i = 0;
2844     while ((val = value_generator (&i)))
2845       {
2846         TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2847
2848         node_append_child (node, val);
2849
2850         run_test_nodes (&node, 1);
2851
2852         _dbus_list_clear (&container->children);
2853         node_destroy (val);
2854       }
2855
2856     node_destroy (node);
2857   }
2858
2859   start_next_test ("Each container of each container of each value %d iterations\n",
2860                    N_CONTAINERS * N_CONTAINERS * N_VALUES);
2861   for (i = 0; i < N_CONTAINERS; i++)
2862     {
2863       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2864       TestTypeNode *outer_container = node_new (outer_container_klass);
2865
2866       for (j = 0; j < N_CONTAINERS; j++)
2867         {
2868           TestTypeNode *child;
2869           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2870           TestTypeNode *inner_container = node_new (inner_container_klass);
2871
2872           node_append_child (outer_container, inner_container);
2873
2874           m = 0;
2875           while ((child = value_generator (&m)))
2876             {
2877               node_append_child (inner_container, child);
2878
2879               run_test_nodes (&outer_container, 1);
2880
2881               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2882               node_destroy (child);
2883             }
2884           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2885           node_destroy (inner_container);
2886         }
2887       node_destroy (outer_container);
2888     }
2889
2890   start_next_test ("Each container of each container of each container of each value %d iterations\n",
2891                    N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2892   for (i = 0; i < N_CONTAINERS; i++)
2893     {
2894       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2895       TestTypeNode *outer_container = node_new (outer_container_klass);
2896
2897       for (j = 0; j < N_CONTAINERS; j++)
2898         {
2899           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2900           TestTypeNode *inner_container = node_new (inner_container_klass);
2901
2902           node_append_child (outer_container, inner_container);
2903
2904           for (k = 0; k < N_CONTAINERS; k++)
2905             {
2906               TestTypeNode *child;
2907               const TestTypeNodeClass *center_container_klass = container_nodes[k];
2908               TestTypeNode *center_container = node_new (center_container_klass);
2909
2910               node_append_child (inner_container, center_container);
2911
2912               m = 0;
2913               while ((child = value_generator (&m)))
2914                 {
2915                   node_append_child (center_container, child);
2916
2917                   run_test_nodes (&outer_container, 1);
2918
2919                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2920                   node_destroy (child);
2921                 }
2922               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2923               node_destroy (center_container);
2924             }
2925           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2926           node_destroy (inner_container);
2927         }
2928       node_destroy (outer_container);
2929     }
2930
2931 #if 0
2932   /* This one takes a really long time, so comment it out for now */
2933   start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2934                    N_VALUES * N_VALUES * N_VALUES);
2935   {
2936     TestTypeNode *nodes[3];
2937
2938     i = 0;
2939     while ((nodes[0] = value_generator (&i)))
2940       {
2941         j = 0;
2942         while ((nodes[1] = value_generator (&j)))
2943           {
2944             k = 0;
2945             while ((nodes[2] = value_generator (&k)))
2946               {
2947                 run_test_nodes (nodes, 3);
2948
2949                 node_destroy (nodes[2]);
2950               }
2951             node_destroy (nodes[1]);
2952           }
2953         node_destroy (nodes[0]);
2954       }
2955   }
2956 #endif /* #if 0 expensive test */
2957
2958   fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
2959            n_iterations_completed_total);
2960   fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
2961            MAX_INITIAL_OFFSET);
2962   fprintf (stderr, "out of memory handling %s tested\n",
2963            TEST_OOM_HANDLING ? "was" : "was not");
2964 }
2965
2966 dbus_bool_t _dbus_marshal_recursive_test (void);
2967
2968 dbus_bool_t
2969 _dbus_marshal_recursive_test (void)
2970 {
2971   make_and_run_test_nodes ();
2972
2973   return TRUE;
2974 }
2975
2976 #if 1
2977 dbus_bool_t _dbus_marshal_test (void);
2978 int
2979 main (int argc, char **argv)
2980 {
2981   _dbus_marshal_test ();
2982
2983   _dbus_marshal_recursive_test ();
2984
2985   return 0;
2986 }
2987 #endif /* main() */
2988
2989
2990 /*
2991  *
2992  *
2993  *         Implementations of each type node class
2994  *
2995  *
2996  *
2997  */
2998
2999
3000 #define SAMPLE_INT32           12345678
3001 #define SAMPLE_INT32_ALTERNATE 53781429
3002 static dbus_int32_t
3003 int32_from_seed (int seed)
3004 {
3005   /* Generate an integer value that's predictable from seed.  We could
3006    * just use seed itself, but that would only ever touch one byte of
3007    * the int so would miss some kinds of bug.
3008    */
3009   dbus_int32_t v;
3010
3011   v = 42; /* just to quiet compiler afaik */
3012   switch (seed % 5)
3013     {
3014     case 0:
3015       v = SAMPLE_INT32;
3016       break;
3017     case 1:
3018       v = SAMPLE_INT32_ALTERNATE;
3019       break;
3020     case 2:
3021       v = -1;
3022       break;
3023     case 3:
3024       v = _DBUS_INT_MAX;
3025       break;
3026     case 4:
3027       v = 1;
3028       break;
3029     }
3030
3031   if (seed > 1)
3032     v *= seed; /* wraps around eventually, which is fine */
3033
3034   return v;
3035 }
3036
3037 static dbus_bool_t
3038 int32_write_value (TestTypeNode   *node,
3039                    DataBlock      *block,
3040                    DBusTypeWriter *writer,
3041                    int             seed)
3042 {
3043   /* also used for uint32 */
3044   dbus_int32_t v;
3045
3046   v = int32_from_seed (seed);
3047
3048   return _dbus_type_writer_write_basic (writer,
3049                                         node->klass->typecode,
3050                                         &v);
3051 }
3052
3053 static dbus_bool_t
3054 int32_read_value (TestTypeNode   *node,
3055                   DataBlock      *block,
3056                   DBusTypeReader *reader,
3057                   int             seed)
3058 {
3059   /* also used for uint32 */
3060   dbus_int32_t v;
3061
3062   check_expected_type (reader, node->klass->typecode);
3063
3064   _dbus_type_reader_read_basic (reader,
3065                                 (dbus_int32_t*) &v);
3066
3067   _dbus_assert (v == int32_from_seed (seed));
3068
3069   return TRUE;
3070 }
3071
3072 #ifdef DBUS_HAVE_INT64
3073 static dbus_int64_t
3074 int64_from_seed (int seed)
3075 {
3076   dbus_int32_t v32;
3077   dbus_int64_t v;
3078
3079   v32 = int32_from_seed (seed);
3080
3081   v = - (dbus_int32_t) ~ v32;
3082   v |= (((dbus_int64_t)v32) << 32);
3083
3084   return v;
3085 }
3086 #endif
3087
3088 static dbus_bool_t
3089 int64_write_value (TestTypeNode   *node,
3090                    DataBlock      *block,
3091                    DBusTypeWriter *writer,
3092                    int             seed)
3093 {
3094 #ifdef DBUS_HAVE_INT64
3095   /* also used for uint64 */
3096   dbus_int64_t v;
3097
3098   v = int64_from_seed (seed);
3099
3100   return _dbus_type_writer_write_basic (writer,
3101                                         node->klass->typecode,
3102                                         &v);
3103 #else
3104   return TRUE;
3105 #endif
3106 }
3107
3108 static dbus_bool_t
3109 int64_read_value (TestTypeNode   *node,
3110                   DataBlock      *block,
3111                   DBusTypeReader *reader,
3112                   int             seed)
3113 {
3114 #ifdef DBUS_HAVE_INT64
3115   /* also used for uint64 */
3116   dbus_int64_t v;
3117
3118   check_expected_type (reader, node->klass->typecode);
3119
3120   _dbus_type_reader_read_basic (reader,
3121                                 (dbus_int64_t*) &v);
3122
3123   _dbus_assert (v == int64_from_seed (seed));
3124
3125   return TRUE;
3126 #else
3127   return TRUE;
3128 #endif
3129 }
3130
3131 #define MAX_SAMPLE_STRING_LEN 10
3132 static void
3133 string_from_seed (char *buf,
3134                   int   len,
3135                   int   seed)
3136 {
3137   int i;
3138   unsigned char v;
3139
3140   _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
3141
3142   v = (unsigned char) ('A' + seed);
3143
3144   i = 0;
3145   while (i < len)
3146     {
3147       if (v < 'A' || v > 'z')
3148         v = 'A';
3149
3150       buf[i] = v;
3151
3152       v += 1;
3153       ++i;
3154     }
3155
3156   buf[i] = '\0';
3157 }
3158
3159 static dbus_bool_t
3160 string_write_value (TestTypeNode   *node,
3161                     DataBlock      *block,
3162                     DBusTypeWriter *writer,
3163                     int             seed)
3164 {
3165   char buf[MAX_SAMPLE_STRING_LEN];
3166   const char *v_string = buf;
3167
3168   string_from_seed (buf, node->klass->subclass_detail,
3169                     seed);
3170
3171   return _dbus_type_writer_write_basic (writer,
3172                                         node->klass->typecode,
3173                                         &v_string);
3174 }
3175
3176 static dbus_bool_t
3177 string_read_value (TestTypeNode   *node,
3178                    DataBlock      *block,
3179                    DBusTypeReader *reader,
3180                    int             seed)
3181 {
3182   const char *v;
3183   char buf[MAX_SAMPLE_STRING_LEN];
3184
3185   check_expected_type (reader, node->klass->typecode);
3186
3187   _dbus_type_reader_read_basic (reader,
3188                                 (const char **) &v);
3189
3190   string_from_seed (buf, node->klass->subclass_detail,
3191                     seed);
3192
3193   if (strcmp (buf, v) != 0)
3194     {
3195       _dbus_warn ("read string '%s' expected '%s'\n",
3196                   v, buf);
3197       _dbus_assert_not_reached ("test failed");
3198     }
3199
3200   return TRUE;
3201 }
3202
3203 #define BOOL_FROM_SEED(seed) (seed % 2)
3204
3205 static dbus_bool_t
3206 bool_write_value (TestTypeNode   *node,
3207                   DataBlock      *block,
3208                   DBusTypeWriter *writer,
3209                   int             seed)
3210 {
3211   unsigned char v;
3212
3213   v = BOOL_FROM_SEED (seed);
3214
3215   return _dbus_type_writer_write_basic (writer,
3216                                         node->klass->typecode,
3217                                         &v);
3218 }
3219
3220 static dbus_bool_t
3221 bool_read_value (TestTypeNode   *node,
3222                  DataBlock      *block,
3223                  DBusTypeReader *reader,
3224                  int             seed)
3225 {
3226   unsigned char v;
3227
3228   check_expected_type (reader, node->klass->typecode);
3229
3230   _dbus_type_reader_read_basic (reader,
3231                                 (unsigned char*) &v);
3232
3233   _dbus_assert (v == BOOL_FROM_SEED (seed));
3234
3235   return TRUE;
3236 }
3237
3238 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
3239
3240 static dbus_bool_t
3241 byte_write_value (TestTypeNode   *node,
3242                   DataBlock      *block,
3243                   DBusTypeWriter *writer,
3244                   int             seed)
3245 {
3246   unsigned char v;
3247
3248   v = BYTE_FROM_SEED (seed);
3249
3250   return _dbus_type_writer_write_basic (writer,
3251                                         node->klass->typecode,
3252                                         &v);
3253 }
3254
3255 static dbus_bool_t
3256 byte_read_value (TestTypeNode   *node,
3257                  DataBlock      *block,
3258                  DBusTypeReader *reader,
3259                  int             seed)
3260 {
3261   unsigned char v;
3262
3263   check_expected_type (reader, node->klass->typecode);
3264
3265   _dbus_type_reader_read_basic (reader,
3266                                 (unsigned char*) &v);
3267
3268   _dbus_assert (v == BYTE_FROM_SEED (seed));
3269
3270   return TRUE;
3271 }
3272
3273 static double
3274 double_from_seed (int seed)
3275 {
3276   return SAMPLE_INT32 * (double) seed + 0.3;
3277 }
3278
3279 static dbus_bool_t
3280 double_write_value (TestTypeNode   *node,
3281                     DataBlock      *block,
3282                     DBusTypeWriter *writer,
3283                     int             seed)
3284 {
3285   double v;
3286
3287   v = double_from_seed (seed);
3288
3289   return _dbus_type_writer_write_basic (writer,
3290                                         node->klass->typecode,
3291                                         &v);
3292 }
3293
3294 static dbus_bool_t
3295 double_read_value (TestTypeNode   *node,
3296                    DataBlock      *block,
3297                    DBusTypeReader *reader,
3298                    int             seed)
3299 {
3300   double v;
3301   double expected;
3302
3303   check_expected_type (reader, node->klass->typecode);
3304
3305   _dbus_type_reader_read_basic (reader,
3306                                 (double*) &v);
3307
3308   expected = double_from_seed (seed);
3309
3310   if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
3311     {
3312 #ifdef DBUS_HAVE_INT64
3313       _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
3314                   expected, v,
3315                   *(dbus_uint64_t*)&expected,
3316                   *(dbus_uint64_t*)&v);
3317 #endif
3318       _dbus_assert_not_reached ("test failed");
3319     }
3320
3321   return TRUE;
3322 }
3323
3324
3325 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
3326 static void
3327 object_path_from_seed (char *buf,
3328                        int   seed)
3329 {
3330   int i;
3331   unsigned char v;
3332
3333   v = (unsigned char) ('A' + seed);
3334
3335   i = 0;
3336   while (i < 8)
3337     {
3338       if (v < 'A' || v > 'z')
3339         v = 'A';
3340
3341       buf[i] = '/';
3342       ++i;
3343       buf[i] = v;
3344       ++i;
3345
3346       v += 1;
3347     }
3348
3349   buf[i] = '\0';
3350 }
3351
3352 static dbus_bool_t
3353 object_path_write_value (TestTypeNode   *node,
3354                          DataBlock      *block,
3355                          DBusTypeWriter *writer,
3356                          int             seed)
3357 {
3358   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3359   const char *v_string = buf;
3360
3361   object_path_from_seed (buf, seed);
3362
3363   return _dbus_type_writer_write_basic (writer,
3364                                         node->klass->typecode,
3365                                         &v_string);
3366 }
3367
3368 static dbus_bool_t
3369 object_path_read_value (TestTypeNode   *node,
3370                         DataBlock      *block,
3371                         DBusTypeReader *reader,
3372                         int             seed)
3373 {
3374   const char *v;
3375   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3376
3377   check_expected_type (reader, node->klass->typecode);
3378
3379   _dbus_type_reader_read_basic (reader,
3380                                 (const char **) &v);
3381
3382   object_path_from_seed (buf, seed);
3383
3384   if (strcmp (buf, v) != 0)
3385     {
3386       _dbus_warn ("read object path '%s' expected '%s'\n",
3387                   v, buf);
3388       _dbus_assert_not_reached ("test failed");
3389     }
3390
3391   return TRUE;
3392 }
3393
3394
3395 #define MAX_SAMPLE_SIGNATURE_LEN 10
3396 static void
3397 signature_from_seed (char *buf,
3398                      int   seed)
3399 {
3400   int i;
3401   const char *s;
3402   const char *sample_signatures[] = {
3403     "",
3404     "ai",
3405     "x",
3406     "a(ii)",
3407     "asax"
3408   };
3409
3410   s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
3411
3412   for (i = 0; s[i]; i++)
3413     {
3414       buf[i] = s[i];
3415     }
3416   buf[i] = '\0';
3417 }
3418
3419 static dbus_bool_t
3420 signature_write_value (TestTypeNode   *node,
3421                        DataBlock      *block,
3422                        DBusTypeWriter *writer,
3423                        int             seed)
3424 {
3425   char buf[MAX_SAMPLE_SIGNATURE_LEN];
3426   const char *v_string = buf;
3427
3428   signature_from_seed (buf, seed);
3429
3430   return _dbus_type_writer_write_basic (writer,
3431                                         node->klass->typecode,
3432                                         &v_string);
3433 }
3434
3435 static dbus_bool_t
3436 signature_read_value (TestTypeNode   *node,
3437                       DataBlock      *block,
3438                       DBusTypeReader *reader,
3439                       int             seed)
3440 {
3441   const char *v;
3442   char buf[MAX_SAMPLE_SIGNATURE_LEN];
3443
3444   check_expected_type (reader, node->klass->typecode);
3445
3446   _dbus_type_reader_read_basic (reader,
3447                                 (const char **) &v);
3448
3449   signature_from_seed (buf, seed);
3450
3451   if (strcmp (buf, v) != 0)
3452     {
3453       _dbus_warn ("read signature value '%s' expected '%s'\n",
3454                   v, buf);
3455       _dbus_assert_not_reached ("test failed");
3456     }
3457
3458   return TRUE;
3459 }
3460
3461 static dbus_bool_t
3462 struct_write_value (TestTypeNode   *node,
3463                     DataBlock      *block,
3464                     DBusTypeWriter *writer,
3465                     int             seed)
3466 {
3467   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3468   DataBlockState saved;
3469   DBusTypeWriter sub;
3470   int i;
3471   int n_copies;
3472
3473   n_copies = node->klass->subclass_detail;
3474
3475   _dbus_assert (container->children != NULL);
3476
3477   data_block_save (block, &saved);
3478
3479   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT,
3480                                   NULL, 0,
3481                                   &sub))
3482     return FALSE;
3483
3484   i = 0;
3485   while (i < n_copies)
3486     {
3487       DBusList *link;
3488
3489       link = _dbus_list_get_first_link (&container->children);
3490       while (link != NULL)
3491         {
3492           TestTypeNode *child = link->data;
3493           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3494
3495           if (!node_write_value (child, block, &sub, i))
3496             {
3497               data_block_restore (block, &saved);
3498               return FALSE;
3499             }
3500
3501           link = next;
3502         }
3503
3504       ++i;
3505     }
3506
3507   if (!_dbus_type_writer_unrecurse (writer, &sub))
3508     {
3509       data_block_restore (block, &saved);
3510       return FALSE;
3511     }
3512
3513   return TRUE;
3514 }
3515
3516 static dbus_bool_t
3517 struct_read_value (TestTypeNode   *node,
3518                    DataBlock      *block,
3519                    DBusTypeReader *reader,
3520                    int             seed)
3521 {
3522   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3523   DBusTypeReader sub;
3524   int i;
3525   int n_copies;
3526
3527   n_copies = node->klass->subclass_detail;
3528
3529   check_expected_type (reader, DBUS_TYPE_STRUCT);
3530
3531   _dbus_type_reader_recurse (reader, &sub);
3532
3533   i = 0;
3534   while (i < n_copies)
3535     {
3536       DBusList *link;
3537
3538       link = _dbus_list_get_first_link (&container->children);
3539       while (link != NULL)
3540         {
3541           TestTypeNode *child = link->data;
3542           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3543
3544           if (!node_read_value (child, block, &sub, i))
3545             return FALSE;
3546
3547           if (i == (n_copies - 1) && next == NULL)
3548             NEXT_EXPECTING_FALSE (&sub);
3549           else
3550             NEXT_EXPECTING_TRUE (&sub);
3551
3552           link = next;
3553         }
3554
3555       ++i;
3556     }
3557
3558   return TRUE;
3559 }
3560
3561 static dbus_bool_t
3562 struct_build_signature (TestTypeNode   *node,
3563                         DBusString     *str)
3564 {
3565   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3566   int i;
3567   int orig_len;
3568   int n_copies;
3569
3570   n_copies = node->klass->subclass_detail;
3571
3572   orig_len = _dbus_string_get_length (str);
3573
3574   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3575     goto oom;
3576
3577   i = 0;
3578   while (i < n_copies)
3579     {
3580       DBusList *link;
3581
3582       link = _dbus_list_get_first_link (&container->children);
3583       while (link != NULL)
3584         {
3585           TestTypeNode *child = link->data;
3586           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3587
3588           if (!node_build_signature (child, str))
3589             goto oom;
3590
3591           link = next;
3592         }
3593
3594       ++i;
3595     }
3596
3597   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3598     goto oom;
3599
3600   return TRUE;
3601
3602  oom:
3603   _dbus_string_set_length (str, orig_len);
3604   return FALSE;
3605 }
3606
3607 static dbus_bool_t
3608 array_write_value (TestTypeNode   *node,
3609                    DataBlock      *block,
3610                    DBusTypeWriter *writer,
3611                    int             seed)
3612 {
3613   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3614   DataBlockState saved;
3615   DBusTypeWriter sub;
3616   DBusString element_signature;
3617   int i;
3618   int n_copies;
3619
3620   n_copies = node->klass->subclass_detail;
3621
3622   _dbus_assert (container->children != NULL);
3623
3624   data_block_save (block, &saved);
3625
3626   if (!_dbus_string_init (&element_signature))
3627     return FALSE;
3628
3629   if (!node_build_signature (_dbus_list_get_first (&container->children),
3630                              &element_signature))
3631     goto oom;
3632
3633   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
3634                                   &element_signature, 0,
3635                                   &sub))
3636     goto oom;
3637
3638   i = 0;
3639   while (i < n_copies)
3640     {
3641       DBusList *link;
3642
3643       link = _dbus_list_get_first_link (&container->children);
3644       while (link != NULL)
3645         {
3646           TestTypeNode *child = link->data;
3647           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3648
3649           if (!node_write_value (child, block, &sub, i))
3650             goto oom;
3651
3652           link = next;
3653         }
3654
3655       ++i;
3656     }
3657
3658   if (!_dbus_type_writer_unrecurse (writer, &sub))
3659     goto oom;
3660
3661   _dbus_string_free (&element_signature);
3662   return TRUE;
3663
3664  oom:
3665   data_block_restore (block, &saved);
3666   _dbus_string_free (&element_signature);
3667   return FALSE;
3668 }
3669
3670 static dbus_bool_t
3671 array_read_value (TestTypeNode   *node,
3672                   DataBlock      *block,
3673                   DBusTypeReader *reader,
3674                   int             seed)
3675 {
3676   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3677   DBusTypeReader sub;
3678   int i;
3679   int n_copies;
3680
3681   n_copies = node->klass->subclass_detail;
3682
3683   check_expected_type (reader, DBUS_TYPE_ARRAY);
3684
3685   if (n_copies > 0)
3686     {
3687       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3688
3689       _dbus_type_reader_recurse (reader, &sub);
3690
3691       i = 0;
3692       while (i < n_copies)
3693         {
3694           DBusList *link;
3695
3696           link = _dbus_list_get_first_link (&container->children);
3697           while (link != NULL)
3698             {
3699               TestTypeNode *child = link->data;
3700               DBusList *next = _dbus_list_get_next_link (&container->children, link);
3701
3702               if (!node_read_value (child, block, &sub, i))
3703                 return FALSE;
3704
3705               if (i == (n_copies - 1) && next == NULL)
3706                 NEXT_EXPECTING_FALSE (&sub);
3707               else
3708                 NEXT_EXPECTING_TRUE (&sub);
3709
3710               link = next;
3711             }
3712
3713           ++i;
3714         }
3715     }
3716   else
3717     {
3718       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3719     }
3720
3721   return TRUE;
3722 }
3723
3724 static dbus_bool_t
3725 array_build_signature (TestTypeNode   *node,
3726                        DBusString     *str)
3727 {
3728   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3729   int orig_len;
3730
3731   orig_len = _dbus_string_get_length (str);
3732
3733   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3734     goto oom;
3735
3736   if (!node_build_signature (_dbus_list_get_first (&container->children),
3737                              str))
3738     goto oom;
3739
3740   return TRUE;
3741
3742  oom:
3743   _dbus_string_set_length (str, orig_len);
3744   return FALSE;
3745 }
3746
3747  /* 10 is random just to add another seed that we use in the suite */
3748 #define VARIANT_SEED 10
3749
3750 static dbus_bool_t
3751 variant_write_value (TestTypeNode   *node,
3752                      DataBlock      *block,
3753                      DBusTypeWriter *writer,
3754                      int             seed)
3755 {
3756   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3757   DataBlockState saved;
3758   DBusTypeWriter sub;
3759   DBusString content_signature;
3760   TestTypeNode *child;
3761
3762   _dbus_assert (container->children != NULL);
3763   _dbus_assert (_dbus_list_length_is_one (&container->children));
3764
3765   child = _dbus_list_get_first (&container->children);
3766
3767   data_block_save (block, &saved);
3768
3769   if (!_dbus_string_init (&content_signature))
3770     return FALSE;
3771
3772   if (!node_build_signature (child,
3773                              &content_signature))
3774     goto oom;
3775
3776   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT,
3777                                   &content_signature, 0,
3778                                   &sub))
3779     goto oom;
3780
3781   if (!node_write_value (child, block, &sub, VARIANT_SEED))
3782     goto oom;
3783
3784   if (!_dbus_type_writer_unrecurse (writer, &sub))
3785     goto oom;
3786
3787   _dbus_string_free (&content_signature);
3788   return TRUE;
3789
3790  oom:
3791   data_block_restore (block, &saved);
3792   _dbus_string_free (&content_signature);
3793   return FALSE;
3794 }
3795
3796 static dbus_bool_t
3797 variant_read_value (TestTypeNode   *node,
3798                     DataBlock      *block,
3799                     DBusTypeReader *reader,
3800                     int             seed)
3801 {
3802   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3803   DBusTypeReader sub;
3804   TestTypeNode *child;
3805
3806   _dbus_assert (container->children != NULL);
3807   _dbus_assert (_dbus_list_length_is_one (&container->children));
3808
3809   child = _dbus_list_get_first (&container->children);
3810
3811   check_expected_type (reader, DBUS_TYPE_VARIANT);
3812
3813   _dbus_type_reader_recurse (reader, &sub);
3814
3815   if (!node_read_value (child, block, &sub, VARIANT_SEED))
3816     return FALSE;
3817
3818   NEXT_EXPECTING_FALSE (&sub);
3819
3820   return TRUE;
3821 }
3822
3823 static void
3824 container_destroy (TestTypeNode *node)
3825 {
3826   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3827   DBusList *link;
3828
3829   link = _dbus_list_get_first_link (&container->children);
3830   while (link != NULL)
3831     {
3832       TestTypeNode *child = link->data;
3833       DBusList *next = _dbus_list_get_next_link (&container->children, link);
3834
3835       node_destroy (child);
3836
3837       _dbus_list_free_link (link);
3838
3839       link = next;
3840     }
3841 }
3842
3843 #endif /* DBUS_BUILD_TESTS */