yay, variant values working before the new year.
[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   dbus_bool_t   (* construct)     (TestTypeNode   *node);
1427   void          (* destroy)       (TestTypeNode   *node);
1428
1429   dbus_bool_t (* write_value)     (TestTypeNode   *node,
1430                                    DataBlock      *block,
1431                                    DBusTypeWriter *writer,
1432                                    int             seed);
1433   dbus_bool_t (* read_value)      (TestTypeNode   *node,
1434                                    DataBlock      *block,
1435                                    DBusTypeReader *reader,
1436                                    int             seed);
1437   dbus_bool_t (* build_signature) (TestTypeNode   *node,
1438                                    DBusString     *str);
1439 };
1440
1441 struct TestTypeNodeContainerClass
1442 {
1443   TestTypeNodeClass base;
1444 };
1445
1446 static dbus_bool_t int32_write_value        (TestTypeNode   *node,
1447                                              DataBlock      *block,
1448                                              DBusTypeWriter *writer,
1449                                              int             seed);
1450 static dbus_bool_t int32_read_value         (TestTypeNode   *node,
1451                                              DataBlock      *block,
1452                                              DBusTypeReader *reader,
1453                                              int             seed);
1454 static dbus_bool_t int64_write_value        (TestTypeNode   *node,
1455                                              DataBlock      *block,
1456                                              DBusTypeWriter *writer,
1457                                              int             seed);
1458 static dbus_bool_t int64_read_value         (TestTypeNode   *node,
1459                                              DataBlock      *block,
1460                                              DBusTypeReader *reader,
1461                                              int             seed);
1462 static dbus_bool_t struct_1_write_value     (TestTypeNode   *node,
1463                                              DataBlock      *block,
1464                                              DBusTypeWriter *writer,
1465                                              int             seed);
1466 static dbus_bool_t struct_1_read_value      (TestTypeNode   *node,
1467                                              DataBlock      *block,
1468                                              DBusTypeReader *reader,
1469                                              int             seed);
1470 static dbus_bool_t struct_1_build_signature (TestTypeNode   *node,
1471                                              DBusString     *str);
1472 static dbus_bool_t struct_2_write_value     (TestTypeNode   *node,
1473                                              DataBlock      *block,
1474                                              DBusTypeWriter *writer,
1475                                              int             seed);
1476 static dbus_bool_t struct_2_read_value      (TestTypeNode   *node,
1477                                              DataBlock      *block,
1478                                              DBusTypeReader *reader,
1479                                              int             seed);
1480 static dbus_bool_t struct_2_build_signature (TestTypeNode   *node,
1481                                              DBusString     *str);
1482 static dbus_bool_t array_build_signature    (TestTypeNode   *node,
1483                                              DBusString     *str);
1484 static dbus_bool_t array_1_write_value      (TestTypeNode   *node,
1485                                              DataBlock      *block,
1486                                              DBusTypeWriter *writer,
1487                                              int             seed);
1488 static dbus_bool_t array_1_read_value       (TestTypeNode   *node,
1489                                              DataBlock      *block,
1490                                              DBusTypeReader *reader,
1491                                              int             seed);
1492 static dbus_bool_t array_0_write_value      (TestTypeNode   *node,
1493                                              DataBlock      *block,
1494                                              DBusTypeWriter *writer,
1495                                              int             seed);
1496 static dbus_bool_t array_0_read_value       (TestTypeNode   *node,
1497                                              DataBlock      *block,
1498                                              DBusTypeReader *reader,
1499                                              int             seed);
1500 static dbus_bool_t array_2_write_value      (TestTypeNode   *node,
1501                                              DataBlock      *block,
1502                                              DBusTypeWriter *writer,
1503                                              int             seed);
1504 static dbus_bool_t array_2_read_value       (TestTypeNode   *node,
1505                                              DataBlock      *block,
1506                                              DBusTypeReader *reader,
1507                                              int             seed);
1508 static dbus_bool_t array_9_write_value      (TestTypeNode   *node,
1509                                              DataBlock      *block,
1510                                              DBusTypeWriter *writer,
1511                                              int             seed);
1512 static dbus_bool_t array_9_read_value       (TestTypeNode   *node,
1513                                              DataBlock      *block,
1514                                              DBusTypeReader *reader,
1515                                              int             seed);
1516 static dbus_bool_t variant_write_value      (TestTypeNode   *node,
1517                                              DataBlock      *block,
1518                                              DBusTypeWriter *writer,
1519                                              int             seed);
1520 static dbus_bool_t variant_read_value       (TestTypeNode   *node,
1521                                              DataBlock      *block,
1522                                              DBusTypeReader *reader,
1523                                              int             seed);
1524 static void        container_destroy        (TestTypeNode   *node);
1525
1526
1527
1528 static const TestTypeNodeClass int32_class = {
1529   DBUS_TYPE_INT32,
1530   sizeof (TestTypeNode),
1531   NULL,
1532   NULL,
1533   int32_write_value,
1534   int32_read_value,
1535   NULL
1536 };
1537
1538 static const TestTypeNodeClass uint32_class = {
1539   DBUS_TYPE_UINT32,
1540   sizeof (TestTypeNode),
1541   NULL,
1542   NULL,
1543   int32_write_value, /* recycle from int32 */
1544   int32_read_value,  /* recycle from int32 */
1545   NULL
1546 };
1547
1548 static const TestTypeNodeClass int64_class = {
1549   DBUS_TYPE_INT64,
1550   sizeof (TestTypeNode),
1551   NULL,
1552   NULL,
1553   int64_write_value,
1554   int64_read_value,
1555   NULL
1556 };
1557
1558 static const TestTypeNodeClass uint64_class = {
1559   DBUS_TYPE_UINT64,
1560   sizeof (TestTypeNode),
1561   NULL,
1562   NULL,
1563   int64_write_value, /* recycle from int64 */
1564   int64_read_value,  /* recycle from int64 */
1565   NULL
1566 };
1567
1568 static const TestTypeNodeClass struct_1_class = {
1569   DBUS_TYPE_STRUCT,
1570   sizeof (TestTypeNodeContainer),
1571   NULL,
1572   container_destroy,
1573   struct_1_write_value,
1574   struct_1_read_value,
1575   struct_1_build_signature
1576 };
1577
1578 static const TestTypeNodeClass struct_2_class = {
1579   DBUS_TYPE_STRUCT,
1580   sizeof (TestTypeNodeContainer),
1581   NULL,
1582   container_destroy,
1583   struct_2_write_value,
1584   struct_2_read_value,
1585   struct_2_build_signature
1586 };
1587
1588 static const TestTypeNodeClass array_0_class = {
1589   DBUS_TYPE_ARRAY,
1590   sizeof (TestTypeNodeContainer),
1591   NULL,
1592   container_destroy,
1593   array_0_write_value,
1594   array_0_read_value,
1595   array_build_signature
1596 };
1597
1598 static const TestTypeNodeClass array_1_class = {
1599   DBUS_TYPE_ARRAY,
1600   sizeof (TestTypeNodeContainer),
1601   NULL,
1602   container_destroy,
1603   array_1_write_value,
1604   array_1_read_value,
1605   array_build_signature
1606 };
1607
1608 static const TestTypeNodeClass array_2_class = {
1609   DBUS_TYPE_ARRAY,
1610   sizeof (TestTypeNodeContainer),
1611   NULL,
1612   container_destroy,
1613   array_2_write_value,
1614   array_2_read_value,
1615   array_build_signature
1616 };
1617
1618 static const TestTypeNodeClass array_9_class = {
1619   DBUS_TYPE_ARRAY,
1620   sizeof (TestTypeNodeContainer),
1621   NULL,
1622   container_destroy,
1623   array_9_write_value,
1624   array_9_read_value,
1625   array_build_signature
1626 };
1627
1628 static const TestTypeNodeClass variant_class = {
1629   DBUS_TYPE_VARIANT,
1630   sizeof (TestTypeNodeContainer),
1631   NULL,
1632   container_destroy,
1633   variant_write_value,
1634   variant_read_value,
1635   NULL
1636 };
1637
1638 static const TestTypeNodeClass* const
1639 basic_nodes[] = {
1640   &int32_class,
1641   &uint32_class,
1642   &int64_class,
1643   &uint64_class
1644 };
1645 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
1646
1647 static const TestTypeNodeClass* const
1648 container_nodes[] = {
1649   &struct_1_class,
1650   &array_1_class,
1651   &struct_2_class,
1652   &array_0_class,
1653   &array_2_class,
1654   &variant_class
1655   /* array_9_class is omitted on purpose, it's too slow;
1656    * we only use it in one hardcoded test below
1657    */
1658 };
1659 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
1660
1661 static TestTypeNode*
1662 node_new (const TestTypeNodeClass *klass)
1663 {
1664   TestTypeNode *node;
1665
1666   node = dbus_malloc0 (klass->instance_size);
1667   if (node == NULL)
1668     return NULL;
1669
1670   node->klass = klass;
1671
1672   if (klass->construct)
1673     {
1674       if (!(* klass->construct) (node))
1675         {
1676           dbus_free (node);
1677           return FALSE;
1678         }
1679     }
1680
1681   return node;
1682 }
1683
1684 static void
1685 node_destroy (TestTypeNode *node)
1686 {
1687   if (node->klass->destroy)
1688     (* node->klass->destroy) (node);
1689   dbus_free (node);
1690 }
1691
1692 static dbus_bool_t
1693 node_write_value (TestTypeNode   *node,
1694                   DataBlock      *block,
1695                   DBusTypeWriter *writer,
1696                   int             seed)
1697 {
1698   return (* node->klass->write_value) (node, block, writer, seed);
1699 }
1700
1701 static dbus_bool_t
1702 node_read_value (TestTypeNode   *node,
1703                  DataBlock      *block,
1704                  DBusTypeReader *reader,
1705                  int             seed)
1706 {
1707   return (* node->klass->read_value) (node, block, reader, seed);
1708 }
1709
1710 static dbus_bool_t
1711 node_build_signature (TestTypeNode *node,
1712                       DBusString   *str)
1713 {
1714   if (node->klass->build_signature)
1715     return (* node->klass->build_signature) (node, str);
1716   else
1717     return _dbus_string_append_byte (str, node->klass->typecode);
1718 }
1719
1720 static dbus_bool_t
1721 node_append_child (TestTypeNode *node,
1722                    TestTypeNode *child)
1723 {
1724   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
1725
1726   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
1727
1728   if (!_dbus_list_append (&container->children, child))
1729     _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 */
1730
1731   return TRUE;
1732 }
1733
1734 typedef struct
1735 {
1736   const DBusString   *signature;
1737   DataBlock          *block;
1738   int                 type_offset;
1739   int                 byte_order;
1740   TestTypeNode      **nodes;
1741   int                 n_nodes;
1742 } NodeIterationData;
1743
1744 static dbus_bool_t
1745 run_test_nodes_iteration (void *data)
1746 {
1747   NodeIterationData *nid = data;
1748   DBusTypeReader reader;
1749   DBusTypeWriter writer;
1750   int i;
1751
1752   /* Stuff to do:
1753    * 1. write the value
1754    * 2. strcmp-compare with the signature we built
1755    * 3. read the value
1756    * 4. type-iterate the signature and the value and see if they are the same type-wise
1757    */
1758   data_block_init_reader_writer (nid->block,
1759                                  nid->byte_order,
1760                                  &reader, &writer);
1761
1762   i = 0;
1763   while (i < nid->n_nodes)
1764     {
1765       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
1766         return FALSE;
1767
1768       ++i;
1769     }
1770
1771   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
1772                                      &nid->block->signature, nid->type_offset))
1773     {
1774       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
1775                   _dbus_string_get_const_data (nid->signature),
1776                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
1777                   nid->type_offset);
1778       _dbus_assert_not_reached ("wrong signature");
1779     }
1780
1781   i = 0;
1782   while (i < nid->n_nodes)
1783     {
1784       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
1785         return FALSE;
1786
1787       if (i + 1 == nid->n_nodes)
1788         NEXT_EXPECTING_FALSE (&reader);
1789       else
1790         NEXT_EXPECTING_TRUE (&reader);
1791
1792       ++i;
1793     }
1794
1795   /* FIXME type-iterate both signature and value */
1796
1797   return TRUE;
1798 }
1799
1800 static void
1801 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
1802                                      int               n_nodes,
1803                                      const DBusString *signature,
1804                                      int               byte_order,
1805                                      int               initial_offset)
1806 {
1807   DataBlock block;
1808   NodeIterationData nid;
1809
1810   if (!data_block_init (&block))
1811     _dbus_assert_not_reached ("no memory");
1812
1813   if (!_dbus_string_lengthen (&block.signature, initial_offset))
1814     _dbus_assert_not_reached ("no memory");
1815
1816   if (!_dbus_string_lengthen (&block.body, initial_offset))
1817     _dbus_assert_not_reached ("no memory");
1818
1819   nid.signature = signature;
1820   nid.block = &block;
1821   nid.type_offset = initial_offset;
1822   nid.nodes = nodes;
1823   nid.n_nodes = n_nodes;
1824   nid.byte_order = byte_order;
1825
1826   /* FIXME put the OOM testing back once we debug everything and are willing to
1827    * wait for it to run ;-)
1828    */
1829 #if 0
1830   _dbus_test_oom_handling ("running test node",
1831                            run_test_nodes_iteration,
1832                            &nid);
1833 #else
1834   if (!run_test_nodes_iteration (&nid))
1835     _dbus_assert_not_reached ("no memory");
1836 #endif
1837
1838   data_block_free (&block);
1839 }
1840
1841 static void
1842 run_test_nodes (TestTypeNode **nodes,
1843                 int            n_nodes)
1844 {
1845   int i;
1846   DBusString signature;
1847
1848   if (!_dbus_string_init (&signature))
1849     _dbus_assert_not_reached ("no memory");
1850
1851   i = 0;
1852   while (i < n_nodes)
1853     {
1854       if (! node_build_signature (nodes[i], &signature))
1855         _dbus_assert_not_reached ("no memory");
1856
1857       ++i;
1858     }
1859
1860   _dbus_verbose (">>> test nodes with signature '%s'\n",
1861                  _dbus_string_get_const_data (&signature));
1862
1863   /* We do start offset 0 through 9, to get various alignment cases. Still this
1864    * obviously makes the test suite run 10x as slow.
1865    */
1866   i = 0;
1867   while (i < 10)
1868     {
1869       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1870                                            DBUS_LITTLE_ENDIAN, i);
1871       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1872                                            DBUS_BIG_ENDIAN, i);
1873
1874       ++i;
1875     }
1876
1877   _dbus_string_free (&signature);
1878 }
1879
1880 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
1881
1882 static TestTypeNode*
1883 value_generator (int *ip)
1884 {
1885   int i = *ip;
1886   const TestTypeNodeClass *child_klass;
1887   const TestTypeNodeClass *container_klass;
1888   TestTypeNode *child;
1889   TestTypeNode *node;
1890
1891   _dbus_assert (i <= N_VALUES);
1892
1893   if (i == N_VALUES)
1894     {
1895       return NULL;
1896     }
1897   else if (i < N_BASICS)
1898     {
1899       node = node_new (basic_nodes[i]);
1900     }
1901   else
1902     {
1903       /* imagine an array:
1904        * container 0 of basic 0
1905        * container 0 of basic 1
1906        * container 0 of basic 2
1907        * container 1 of basic 0
1908        * container 1 of basic 1
1909        * container 1 of basic 2
1910        */
1911       i -= N_BASICS;
1912
1913       container_klass = container_nodes[i / N_BASICS];
1914       child_klass = basic_nodes[i % N_BASICS];
1915
1916       node = node_new (container_klass);
1917       child = node_new (child_klass);
1918
1919       node_append_child (node, child);
1920     }
1921
1922   *ip += 1; /* increment the generator */
1923
1924   return node;
1925 }
1926
1927 static void
1928 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
1929                                       int                      n_nested)
1930 {
1931   TestTypeNode *root;
1932   TestTypeNode *container;
1933   TestTypeNode *child;
1934   int i;
1935
1936   root = node_new (container_klass);
1937   container = root;
1938   for (i = 1; i < n_nested; i++)
1939     {
1940       child = node_new (container_klass);
1941       node_append_child (container, child);
1942       container = child;
1943     }
1944
1945   /* container should now be the most-nested container */
1946
1947   i = 0;
1948   while ((child = value_generator (&i)))
1949     {
1950       node_append_child (container, child);
1951
1952       run_test_nodes (&root, 1);
1953
1954       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
1955       node_destroy (child);
1956     }
1957
1958   node_destroy (root);
1959 }
1960
1961 static void
1962 make_and_run_test_nodes (void)
1963 {
1964   int i, j, k, m;
1965
1966   /* We try to do this in order of "complicatedness" so that test
1967    * failures tend to show up in the simplest test case that
1968    * demonstrates the failure.  There are also some tests that run
1969    * more than once for this reason, first while going through simple
1970    * cases, second while going through a broader range of complex
1971    * cases.
1972    */
1973   /* Each basic node. The basic nodes should include:
1974    *
1975    * - each fixed-size type (in such a way that it has different values each time,
1976    *                         so we can tell if we mix two of them up)
1977    * - strings of length 0-9
1978    * - object path
1979    * - signature
1980    */
1981   /* Each container node. The container nodes should include:
1982    *
1983    *  struct with 1 and 2 copies of the contained item
1984    *  array with 0, 1, 2 copies of the contained item
1985    *  variant
1986    */
1987   /*  Let a "value" be a basic node, or a container containing a single basic node.
1988    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
1989    *  When iterating through all values to make combinations, do the basic types
1990    *  first and the containers second.
1991    */
1992   /* Each item is shown with its number of iterations to complete so
1993    * we can keep a handle on this unit test
1994    */
1995
1996   /* FIXME test just an empty body, no types at all */
1997
1998   _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
1999                  N_VALUES);
2000   {
2001     TestTypeNode *node;
2002     i = 0;
2003     while ((node = value_generator (&i)))
2004       {
2005         run_test_nodes (&node, 1);
2006
2007         node_destroy (node);
2008       }
2009   }
2010
2011   _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
2012   {
2013     TestTypeNode *nodes[N_VALUES];
2014
2015     i = 0;
2016     while ((nodes[i] = value_generator (&i)))
2017       ;
2018
2019     run_test_nodes (nodes, N_VALUES);
2020
2021     for (i = 0; i < N_VALUES; i++)
2022       node_destroy (nodes[i]);
2023   }
2024
2025   _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
2026                  N_VALUES * N_VALUES * 2);
2027   {
2028     TestTypeNode *nodes[2];
2029
2030     i = 0;
2031     while ((nodes[0] = value_generator (&i)))
2032       {
2033         j = 0;
2034         while ((nodes[1] = value_generator (&j)))
2035           {
2036             run_test_nodes (nodes, 2);
2037
2038             node_destroy (nodes[1]);
2039           }
2040
2041         node_destroy (nodes[0]);
2042       }
2043   }
2044
2045   _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
2046                  N_CONTAINERS * N_VALUES);
2047   for (i = 0; i < N_CONTAINERS; i++)
2048     {
2049       const TestTypeNodeClass *container_klass = container_nodes[i];
2050
2051       make_and_run_values_inside_container (container_klass, 1);
2052     }
2053
2054   _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2055                  N_CONTAINERS * N_VALUES);
2056   for (i = 0; i < N_CONTAINERS; i++)
2057     {
2058       const TestTypeNodeClass *container_klass = container_nodes[i];
2059
2060       make_and_run_values_inside_container (container_klass, 2);
2061     }
2062
2063   _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
2064                  N_CONTAINERS * N_VALUES);
2065   for (i = 0; i < N_CONTAINERS; i++)
2066     {
2067       const TestTypeNodeClass *container_klass = container_nodes[i];
2068
2069       make_and_run_values_inside_container (container_klass, 3);
2070     }
2071
2072   _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
2073                  N_VALUES * N_VALUES);
2074   {
2075     TestTypeNode *val1, *val2;
2076     TestTypeNode *node;
2077
2078     node = node_new (&struct_1_class);
2079
2080     i = 0;
2081     while ((val1 = value_generator (&i)))
2082       {
2083         j = 0;
2084         while ((val2 = value_generator (&j)))
2085           {
2086             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2087
2088             node_append_child (node, val1);
2089             node_append_child (node, val2);
2090
2091             run_test_nodes (&node, 1);
2092
2093             _dbus_list_clear (&container->children);
2094             node_destroy (val2);
2095           }
2096         node_destroy (val1);
2097       }
2098     node_destroy (node);
2099   }
2100
2101   _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
2102   {
2103     TestTypeNode *node;
2104     TestTypeNode *child;
2105
2106     node = node_new (&struct_1_class);
2107
2108     i = 0;
2109     while ((child = value_generator (&i)))
2110       node_append_child (node, child);
2111
2112     run_test_nodes (&node, 1);
2113
2114     node_destroy (node);
2115   }
2116
2117   _dbus_verbose (">>> >>> Each value in a large array %d iterations\n",
2118                  N_VALUES);
2119   {
2120     TestTypeNode *val;
2121     TestTypeNode *node;
2122
2123     node = node_new (&array_9_class);
2124
2125     i = 0;
2126     while ((val = value_generator (&i)))
2127       {
2128         TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2129
2130         node_append_child (node, val);
2131
2132         run_test_nodes (&node, 1);
2133
2134         _dbus_list_clear (&container->children);
2135         node_destroy (val);
2136       }
2137
2138     node_destroy (node);
2139   }
2140
2141   _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
2142                  N_CONTAINERS * N_CONTAINERS * N_VALUES);
2143   for (i = 0; i < N_CONTAINERS; i++)
2144     {
2145       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2146       TestTypeNode *outer_container = node_new (outer_container_klass);
2147
2148       for (j = 0; j < N_CONTAINERS; j++)
2149         {
2150           TestTypeNode *child;
2151           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2152           TestTypeNode *inner_container = node_new (inner_container_klass);
2153
2154           node_append_child (outer_container, inner_container);
2155
2156           m = 0;
2157           while ((child = value_generator (&m)))
2158             {
2159               node_append_child (inner_container, child);
2160
2161               run_test_nodes (&outer_container, 1);
2162
2163               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2164               node_destroy (child);
2165             }
2166           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2167           node_destroy (inner_container);
2168         }
2169       node_destroy (outer_container);
2170     }
2171
2172   _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
2173                  N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2174   for (i = 0; i < N_CONTAINERS; i++)
2175     {
2176       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2177       TestTypeNode *outer_container = node_new (outer_container_klass);
2178
2179       for (j = 0; j < N_CONTAINERS; j++)
2180         {
2181           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2182           TestTypeNode *inner_container = node_new (inner_container_klass);
2183
2184           node_append_child (outer_container, inner_container);
2185
2186           for (k = 0; k < N_CONTAINERS; k++)
2187             {
2188               TestTypeNode *child;
2189               const TestTypeNodeClass *center_container_klass = container_nodes[k];
2190               TestTypeNode *center_container = node_new (center_container_klass);
2191
2192               node_append_child (inner_container, center_container);
2193
2194               m = 0;
2195               while ((child = value_generator (&m)))
2196                 {
2197                   node_append_child (center_container, child);
2198
2199                   run_test_nodes (&outer_container, 1);
2200
2201                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2202                   node_destroy (child);
2203                 }
2204               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2205               node_destroy (center_container);
2206             }
2207           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2208           node_destroy (inner_container);
2209         }
2210       node_destroy (outer_container);
2211     }
2212
2213   _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2214                  N_VALUES * N_VALUES * N_VALUES);
2215   {
2216     TestTypeNode *nodes[3];
2217
2218     i = 0;
2219     while ((nodes[0] = value_generator (&i)))
2220       {
2221         j = 0;
2222         while ((nodes[1] = value_generator (&j)))
2223           {
2224             k = 0;
2225             while ((nodes[2] = value_generator (&k)))
2226               {
2227                 run_test_nodes (nodes, 3);
2228
2229                 node_destroy (nodes[2]);
2230               }
2231             node_destroy (nodes[1]);
2232           }
2233         node_destroy (nodes[0]);
2234       }
2235   }
2236 }
2237
2238 dbus_bool_t _dbus_marshal_recursive_test (void);
2239
2240 dbus_bool_t
2241 _dbus_marshal_recursive_test (void)
2242 {
2243   make_and_run_test_nodes ();
2244
2245   return TRUE;
2246 }
2247
2248 #if 1
2249 int
2250 main (int argc, char **argv)
2251 {
2252   _dbus_marshal_recursive_test ();
2253
2254   return 0;
2255 }
2256 #endif /* main() */
2257
2258
2259 /*
2260  *
2261  *
2262  *         Implementations of each type node class
2263  *
2264  *
2265  *
2266  */
2267
2268 static dbus_int32_t
2269 int32_from_seed (int seed)
2270 {
2271   /* Generate an integer value that's predictable from seed.  We could
2272    * just use seed itself, but that would only ever touch one byte of
2273    * the int so would miss some kinds of bug.
2274    */
2275   dbus_int32_t v;
2276
2277   v = 42; /* just to quiet compiler afaik */
2278   switch (seed % 5)
2279     {
2280     case 0:
2281       v = SAMPLE_INT32;
2282       break;
2283     case 1:
2284       v = SAMPLE_INT32_ALTERNATE;
2285       break;
2286     case 2:
2287       v = -1;
2288       break;
2289     case 3:
2290       v = _DBUS_INT_MAX;
2291       break;
2292     case 4:
2293       v = 1;
2294       break;
2295     }
2296
2297   if (seed > 1)
2298     v *= seed; /* wraps around eventually, which is fine */
2299
2300   return v;
2301 }
2302
2303 static dbus_bool_t
2304 int32_write_value (TestTypeNode   *node,
2305                    DataBlock      *block,
2306                    DBusTypeWriter *writer,
2307                    int             seed)
2308 {
2309   /* also used for uint32 */
2310   dbus_int32_t v;
2311
2312   v = int32_from_seed (seed);
2313
2314   return _dbus_type_writer_write_basic (writer,
2315                                         node->klass->typecode,
2316                                         &v);
2317 }
2318
2319 static dbus_bool_t
2320 int32_read_value (TestTypeNode   *node,
2321                   DataBlock      *block,
2322                   DBusTypeReader *reader,
2323                   int             seed)
2324 {
2325   /* also used for uint32 */
2326   dbus_int32_t v;
2327
2328   check_expected_type (reader, node->klass->typecode);
2329
2330   _dbus_type_reader_read_basic (reader,
2331                                 (dbus_int32_t*) &v);
2332
2333   _dbus_assert (v == int32_from_seed (seed));
2334
2335   return TRUE;
2336 }
2337
2338 #ifdef DBUS_HAVE_INT64
2339 static dbus_int64_t
2340 int64_from_seed (int seed)
2341 {
2342   dbus_int32_t v32;
2343   dbus_int64_t v;
2344
2345   v32 = int32_from_seed (seed);
2346
2347   v = - (dbus_int32_t) ~ v32;
2348   v |= (((dbus_int64_t)v32) << 32);
2349
2350   return v;
2351 }
2352 #endif
2353
2354 static dbus_bool_t
2355 int64_write_value (TestTypeNode   *node,
2356                    DataBlock      *block,
2357                    DBusTypeWriter *writer,
2358                    int             seed)
2359 {
2360 #ifdef DBUS_HAVE_INT64
2361   /* also used for uint64 */
2362   dbus_int64_t v;
2363
2364   v = int64_from_seed (seed);
2365
2366   return _dbus_type_writer_write_basic (writer,
2367                                         node->klass->typecode,
2368                                         &v);
2369 #else
2370   return TRUE;
2371 #endif
2372 }
2373
2374 static dbus_bool_t
2375 int64_read_value (TestTypeNode   *node,
2376                   DataBlock      *block,
2377                   DBusTypeReader *reader,
2378                   int             seed)
2379 {
2380 #ifdef DBUS_HAVE_INT64
2381   /* also used for uint64 */
2382   dbus_int64_t v;
2383
2384   check_expected_type (reader, node->klass->typecode);
2385
2386   _dbus_type_reader_read_basic (reader,
2387                                 (dbus_int64_t*) &v);
2388
2389   _dbus_assert (v == int64_from_seed (seed));
2390
2391   return TRUE;
2392 #else
2393   return TRUE;
2394 #endif
2395 }
2396
2397 static dbus_bool_t
2398 struct_N_write_value (TestTypeNode   *node,
2399                       DataBlock      *block,
2400                       DBusTypeWriter *writer,
2401                       int             n_copies)
2402 {
2403   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2404   DataBlockState saved;
2405   DBusTypeWriter sub;
2406   int i;
2407
2408   _dbus_assert (container->children != NULL);
2409
2410   data_block_save (block, &saved);
2411
2412   if (!_dbus_type_writer_recurse_struct (writer,
2413                                          &sub))
2414     return FALSE;
2415
2416   i = 0;
2417   while (i < n_copies)
2418     {
2419       DBusList *link;
2420
2421       link = _dbus_list_get_first_link (&container->children);
2422       while (link != NULL)
2423         {
2424           TestTypeNode *child = link->data;
2425           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2426
2427           if (!node_write_value (child, block, &sub, i))
2428             {
2429               data_block_restore (block, &saved);
2430               return FALSE;
2431             }
2432
2433           link = next;
2434         }
2435
2436       ++i;
2437     }
2438
2439   if (!_dbus_type_writer_unrecurse (writer, &sub))
2440     {
2441       data_block_restore (block, &saved);
2442       return FALSE;
2443     }
2444
2445   return TRUE;
2446 }
2447
2448 static dbus_bool_t
2449 struct_N_read_value (TestTypeNode   *node,
2450                      DataBlock      *block,
2451                      DBusTypeReader *reader,
2452                      int             n_copies)
2453 {
2454   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2455   DBusTypeReader sub;
2456   int i;
2457
2458   check_expected_type (reader, DBUS_TYPE_STRUCT);
2459
2460   _dbus_type_reader_recurse (reader, &sub);
2461
2462   i = 0;
2463   while (i < n_copies)
2464     {
2465       DBusList *link;
2466
2467       link = _dbus_list_get_first_link (&container->children);
2468       while (link != NULL)
2469         {
2470           TestTypeNode *child = link->data;
2471           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2472
2473           if (!node_read_value (child, block, &sub, i))
2474             return FALSE;
2475
2476           if (i == (n_copies - 1) && next == NULL)
2477             NEXT_EXPECTING_FALSE (&sub);
2478           else
2479             NEXT_EXPECTING_TRUE (&sub);
2480
2481           link = next;
2482         }
2483
2484       ++i;
2485     }
2486
2487   return TRUE;
2488 }
2489
2490 static dbus_bool_t
2491 struct_N_build_signature (TestTypeNode   *node,
2492                           DBusString     *str,
2493                           int             n_copies)
2494 {
2495   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2496   int i;
2497   int orig_len;
2498
2499   orig_len = _dbus_string_get_length (str);
2500
2501   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
2502     goto oom;
2503
2504   i = 0;
2505   while (i < n_copies)
2506     {
2507       DBusList *link;
2508
2509       link = _dbus_list_get_first_link (&container->children);
2510       while (link != NULL)
2511         {
2512           TestTypeNode *child = link->data;
2513           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2514
2515           if (!node_build_signature (child, str))
2516             goto oom;
2517
2518           link = next;
2519         }
2520
2521       ++i;
2522     }
2523
2524   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
2525     goto oom;
2526
2527   return TRUE;
2528
2529  oom:
2530   _dbus_string_set_length (str, orig_len);
2531   return FALSE;
2532 }
2533
2534 static dbus_bool_t
2535 struct_1_write_value (TestTypeNode   *node,
2536                       DataBlock      *block,
2537                       DBusTypeWriter *writer,
2538                       int             seed)
2539 {
2540   return struct_N_write_value (node, block, writer, 1);
2541 }
2542
2543 static dbus_bool_t
2544 struct_1_read_value (TestTypeNode   *node,
2545                      DataBlock      *block,
2546                      DBusTypeReader *reader,
2547                      int             seed)
2548 {
2549   return struct_N_read_value (node, block, reader, 1);
2550 }
2551
2552 static dbus_bool_t
2553 struct_1_build_signature (TestTypeNode   *node,
2554                           DBusString     *str)
2555 {
2556   return struct_N_build_signature (node, str, 1);
2557 }
2558
2559
2560 static dbus_bool_t
2561 struct_2_write_value (TestTypeNode   *node,
2562                       DataBlock      *block,
2563                       DBusTypeWriter *writer,
2564                       int             seed)
2565 {
2566   return struct_N_write_value (node, block, writer, 2);
2567 }
2568
2569 static dbus_bool_t
2570 struct_2_read_value (TestTypeNode   *node,
2571                      DataBlock      *block,
2572                      DBusTypeReader *reader,
2573                      int             seed)
2574 {
2575   return struct_N_read_value (node, block, reader, 2);
2576 }
2577
2578 static dbus_bool_t
2579 struct_2_build_signature (TestTypeNode   *node,
2580                           DBusString     *str)
2581 {
2582   return struct_N_build_signature (node, str, 2);
2583 }
2584
2585 static dbus_bool_t
2586 array_N_write_value (TestTypeNode   *node,
2587                      DataBlock      *block,
2588                      DBusTypeWriter *writer,
2589                      int             n_copies)
2590 {
2591   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2592   DataBlockState saved;
2593   DBusTypeWriter sub;
2594   DBusString element_signature;
2595   int i;
2596
2597   _dbus_assert (container->children != NULL);
2598
2599   data_block_save (block, &saved);
2600
2601   if (!_dbus_string_init (&element_signature))
2602     return FALSE;
2603
2604   if (!node_build_signature (_dbus_list_get_first (&container->children),
2605                              &element_signature))
2606     goto oom;
2607
2608   if (!_dbus_type_writer_recurse_array (writer,
2609                                         _dbus_string_get_const_data (&element_signature),
2610                                         &sub))
2611     goto oom;
2612
2613   i = 0;
2614   while (i < n_copies)
2615     {
2616       DBusList *link;
2617
2618       link = _dbus_list_get_first_link (&container->children);
2619       while (link != NULL)
2620         {
2621           TestTypeNode *child = link->data;
2622           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2623
2624           if (!node_write_value (child, block, &sub, i))
2625             goto oom;
2626
2627           link = next;
2628         }
2629
2630       ++i;
2631     }
2632
2633   if (!_dbus_type_writer_unrecurse (writer, &sub))
2634     goto oom;
2635
2636   _dbus_string_free (&element_signature);
2637   return TRUE;
2638
2639  oom:
2640   data_block_restore (block, &saved);
2641   _dbus_string_free (&element_signature);
2642   return FALSE;
2643 }
2644
2645 static dbus_bool_t
2646 array_N_read_value (TestTypeNode   *node,
2647                     DataBlock      *block,
2648                     DBusTypeReader *reader,
2649                     int             n_copies)
2650 {
2651   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2652   DBusTypeReader sub;
2653   int i;
2654
2655   check_expected_type (reader, DBUS_TYPE_ARRAY);
2656
2657   if (n_copies > 0)
2658     {
2659       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
2660
2661       _dbus_type_reader_recurse (reader, &sub);
2662
2663       i = 0;
2664       while (i < n_copies)
2665         {
2666           DBusList *link;
2667
2668           link = _dbus_list_get_first_link (&container->children);
2669           while (link != NULL)
2670             {
2671               TestTypeNode *child = link->data;
2672               DBusList *next = _dbus_list_get_next_link (&container->children, link);
2673
2674               if (!node_read_value (child, block, &sub, i))
2675                 return FALSE;
2676
2677               if (i == (n_copies - 1) && next == NULL)
2678                 NEXT_EXPECTING_FALSE (&sub);
2679               else
2680                 NEXT_EXPECTING_TRUE (&sub);
2681
2682               link = next;
2683             }
2684
2685           ++i;
2686         }
2687     }
2688   else
2689     {
2690       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
2691     }
2692
2693   return TRUE;
2694 }
2695
2696 static dbus_bool_t
2697 array_build_signature (TestTypeNode   *node,
2698                        DBusString     *str)
2699 {
2700   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2701   int orig_len;
2702
2703   orig_len = _dbus_string_get_length (str);
2704
2705   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
2706     goto oom;
2707
2708   if (!node_build_signature (_dbus_list_get_first (&container->children),
2709                              str))
2710     goto oom;
2711
2712   return TRUE;
2713
2714  oom:
2715   _dbus_string_set_length (str, orig_len);
2716   return FALSE;
2717 }
2718
2719 static dbus_bool_t
2720 array_0_write_value (TestTypeNode   *node,
2721                      DataBlock      *block,
2722                      DBusTypeWriter *writer,
2723                      int             seed)
2724 {
2725   return array_N_write_value (node, block, writer, 0);
2726 }
2727
2728 static dbus_bool_t
2729 array_0_read_value (TestTypeNode   *node,
2730                     DataBlock      *block,
2731                     DBusTypeReader *reader,
2732                     int             seed)
2733 {
2734   return array_N_read_value (node, block, reader, 0);
2735 }
2736
2737
2738 static dbus_bool_t
2739 array_1_write_value (TestTypeNode   *node,
2740                      DataBlock      *block,
2741                      DBusTypeWriter *writer,
2742                      int             seed)
2743 {
2744   return array_N_write_value (node, block, writer, 1);
2745 }
2746
2747 static dbus_bool_t
2748 array_1_read_value (TestTypeNode   *node,
2749                     DataBlock      *block,
2750                     DBusTypeReader *reader,
2751                        int          seed)
2752 {
2753   return array_N_read_value (node, block, reader, 1);
2754 }
2755
2756 static dbus_bool_t
2757 array_2_write_value (TestTypeNode   *node,
2758                      DataBlock      *block,
2759                      DBusTypeWriter *writer,
2760                      int             seed)
2761 {
2762   return array_N_write_value (node, block, writer, 2);
2763 }
2764
2765 static dbus_bool_t
2766 array_2_read_value (TestTypeNode   *node,
2767                     DataBlock      *block,
2768                     DBusTypeReader *reader,
2769                     int             seed)
2770 {
2771   return array_N_read_value (node, block, reader, 2);
2772 }
2773
2774 static dbus_bool_t
2775 array_9_write_value (TestTypeNode   *node,
2776                      DataBlock      *block,
2777                      DBusTypeWriter *writer,
2778                      int             seed)
2779 {
2780   return array_N_write_value (node, block, writer, 9);
2781 }
2782
2783 static dbus_bool_t
2784 array_9_read_value (TestTypeNode   *node,
2785                     DataBlock      *block,
2786                     DBusTypeReader *reader,
2787                     int             seed)
2788 {
2789   return array_N_read_value (node, block, reader, 9);
2790 }
2791
2792  /* 10 is random just to add another seed that we use in the suite */
2793 #define VARIANT_SEED 10
2794
2795 static dbus_bool_t
2796 variant_write_value (TestTypeNode   *node,
2797                      DataBlock      *block,
2798                      DBusTypeWriter *writer,
2799                      int             seed)
2800 {
2801   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2802   DataBlockState saved;
2803   DBusTypeWriter sub;
2804   DBusString content_signature;
2805   TestTypeNode *child;
2806
2807   _dbus_assert (container->children != NULL);
2808   _dbus_assert (_dbus_list_length_is_one (&container->children));
2809
2810   child = _dbus_list_get_first (&container->children);
2811
2812   data_block_save (block, &saved);
2813
2814   if (!_dbus_string_init (&content_signature))
2815     return FALSE;
2816
2817   if (!node_build_signature (child,
2818                              &content_signature))
2819     goto oom;
2820
2821   if (!_dbus_type_writer_recurse_variant (writer,
2822                                           _dbus_string_get_const_data (&content_signature),
2823                                           &sub))
2824     goto oom;
2825
2826   if (!node_write_value (child, block, &sub, VARIANT_SEED))
2827     goto oom;
2828
2829   if (!_dbus_type_writer_unrecurse (writer, &sub))
2830     goto oom;
2831
2832   _dbus_string_free (&content_signature);
2833   return TRUE;
2834
2835  oom:
2836   data_block_restore (block, &saved);
2837   _dbus_string_free (&content_signature);
2838   return FALSE;
2839 }
2840
2841 static dbus_bool_t
2842 variant_read_value (TestTypeNode   *node,
2843                     DataBlock      *block,
2844                     DBusTypeReader *reader,
2845                     int             seed)
2846 {
2847   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2848   DBusTypeReader sub;
2849   TestTypeNode *child;
2850
2851   _dbus_assert (container->children != NULL);
2852   _dbus_assert (_dbus_list_length_is_one (&container->children));
2853
2854   child = _dbus_list_get_first (&container->children);
2855
2856   check_expected_type (reader, DBUS_TYPE_VARIANT);
2857
2858   _dbus_type_reader_recurse (reader, &sub);
2859
2860   if (!node_read_value (child, block, &sub, VARIANT_SEED))
2861     return FALSE;
2862
2863   NEXT_EXPECTING_FALSE (&sub);
2864
2865   return TRUE;
2866 }
2867
2868 static void
2869 container_destroy (TestTypeNode *node)
2870 {
2871   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2872   DBusList *link;
2873
2874   link = _dbus_list_get_first_link (&container->children);
2875   while (link != NULL)
2876     {
2877       TestTypeNode *child = link->data;
2878       DBusList *next = _dbus_list_get_next_link (&container->children, link);
2879
2880       node_destroy (child);
2881
2882       _dbus_list_free_link (link);
2883
2884       link = next;
2885     }
2886 }
2887
2888 #endif /* DBUS_BUILD_TESTS */