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