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