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