test framework extension
[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 static dbus_bool_t
1387 write_int32 (DataBlock      *block,
1388              DBusTypeWriter *writer)
1389 {
1390   dbus_int32_t v = SAMPLE_INT32;
1391
1392   return _dbus_type_writer_write_basic (writer,
1393                                         DBUS_TYPE_INT32,
1394                                         &v);
1395 }
1396
1397 static dbus_bool_t
1398 read_int32 (DataBlock      *block,
1399             DBusTypeReader *reader)
1400 {
1401   dbus_int32_t v;
1402
1403   check_expected_type (reader, DBUS_TYPE_INT32);
1404   
1405   _dbus_type_reader_read_basic (reader,
1406                                 (dbus_int32_t*) &v);
1407
1408   _dbus_assert (v == SAMPLE_INT32);
1409
1410   return TRUE;
1411 }
1412
1413 static dbus_bool_t
1414 write_struct_of_int32 (DataBlock      *block,
1415                        DBusTypeWriter *writer)
1416 {
1417   dbus_int32_t v;
1418   DataBlockState saved;
1419   DBusTypeWriter sub;
1420
1421   data_block_save (block, &saved);
1422   
1423   if (!_dbus_type_writer_recurse_struct (writer,
1424                                   &sub))
1425     return FALSE;
1426
1427   v = SAMPLE_INT32;
1428   if (!_dbus_type_writer_write_basic (&sub,
1429                                       DBUS_TYPE_INT32,
1430                                       &v))
1431     {
1432       data_block_restore (block, &saved);
1433       return FALSE;
1434     }
1435
1436   v = SAMPLE_INT32_ALTERNATE;
1437   if (!_dbus_type_writer_write_basic (&sub,
1438                                       DBUS_TYPE_INT32,
1439                                       &v))
1440     {
1441       data_block_restore (block, &saved);
1442       return FALSE;
1443     }
1444
1445   if (!_dbus_type_writer_unrecurse (writer, &sub))
1446     {
1447       data_block_restore (block, &saved);
1448       return FALSE;
1449     }
1450   
1451   return TRUE;
1452 }
1453
1454 static dbus_bool_t
1455 read_struct_of_int32 (DataBlock      *block,
1456                       DBusTypeReader *reader)
1457 {
1458   dbus_int32_t v;
1459   DBusTypeReader sub;
1460
1461   check_expected_type (reader, DBUS_TYPE_STRUCT);
1462   
1463   _dbus_type_reader_recurse (reader, &sub);
1464
1465   check_expected_type (&sub, DBUS_TYPE_INT32);
1466   
1467   _dbus_type_reader_read_basic (&sub,
1468                                 (dbus_int32_t*) &v);
1469
1470   _dbus_assert (v == SAMPLE_INT32);
1471
1472   NEXT_EXPECTING_TRUE (&sub);
1473   check_expected_type (&sub, DBUS_TYPE_INT32);
1474   
1475   _dbus_type_reader_read_basic (&sub,
1476                                 (dbus_int32_t*) &v);
1477
1478   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1479
1480   NEXT_EXPECTING_FALSE (&sub);
1481   
1482   return TRUE;
1483 }
1484
1485 static dbus_bool_t
1486 write_struct_of_structs (DataBlock      *block,
1487                          DBusTypeWriter *writer)
1488 {
1489   DataBlockState saved;
1490   DBusTypeWriter sub;
1491
1492   data_block_save (block, &saved);
1493   
1494   if (!_dbus_type_writer_recurse_struct (writer,
1495                                          &sub))
1496     return FALSE;
1497
1498   if (!write_struct_of_int32 (block, &sub))
1499     {
1500       data_block_restore (block, &saved);
1501       return FALSE;
1502     }
1503   if (!write_struct_of_int32 (block, &sub))
1504     {
1505       data_block_restore (block, &saved);
1506       return FALSE;
1507     }
1508   if (!write_struct_of_int32 (block, &sub))
1509     {
1510       data_block_restore (block, &saved);
1511       return FALSE;
1512     }
1513
1514   if (!_dbus_type_writer_unrecurse (writer, &sub))
1515     {
1516       data_block_restore (block, &saved);
1517       return FALSE;
1518     }
1519   
1520   return TRUE;
1521 }
1522
1523 static dbus_bool_t
1524 read_struct_of_structs (DataBlock      *block,
1525                         DBusTypeReader *reader)
1526 {
1527   DBusTypeReader sub;
1528   
1529   check_expected_type (reader, DBUS_TYPE_STRUCT);
1530   
1531   _dbus_type_reader_recurse (reader, &sub);
1532
1533   if (!read_struct_of_int32 (block, &sub))
1534     return FALSE;
1535
1536   NEXT_EXPECTING_TRUE (&sub);
1537   if (!read_struct_of_int32 (block, &sub))
1538     return FALSE;
1539
1540   NEXT_EXPECTING_TRUE (&sub);
1541   if (!read_struct_of_int32 (block, &sub))
1542     return FALSE;
1543   
1544   NEXT_EXPECTING_FALSE (&sub);
1545   
1546   return TRUE;
1547 }
1548
1549 static dbus_bool_t
1550 write_struct_of_structs_of_structs (DataBlock      *block,
1551                                     DBusTypeWriter *writer)
1552 {
1553   DataBlockState saved;
1554   DBusTypeWriter sub;
1555
1556   data_block_save (block, &saved);
1557   
1558   if (!_dbus_type_writer_recurse_struct (writer,
1559                                          &sub))
1560     return FALSE;
1561
1562   if (!write_struct_of_structs (block, &sub))
1563     {
1564       data_block_restore (block, &saved);
1565       return FALSE;
1566     }
1567   if (!write_struct_of_structs (block, &sub))
1568     {
1569       data_block_restore (block, &saved);
1570       return FALSE;
1571     }
1572
1573   if (!_dbus_type_writer_unrecurse (writer, &sub))
1574     {
1575       data_block_restore (block, &saved);
1576       return FALSE;
1577     }
1578   
1579   return TRUE;
1580 }
1581
1582 static dbus_bool_t
1583 read_struct_of_structs_of_structs (DataBlock      *block,
1584                                    DBusTypeReader *reader)
1585 {
1586   DBusTypeReader sub;
1587   
1588   check_expected_type (reader, DBUS_TYPE_STRUCT);
1589   
1590   _dbus_type_reader_recurse (reader, &sub);
1591
1592   if (!read_struct_of_structs (block, &sub))
1593     return FALSE;
1594
1595   NEXT_EXPECTING_TRUE (&sub);
1596   if (!read_struct_of_structs (block, &sub))
1597     return FALSE;
1598
1599   NEXT_EXPECTING_FALSE (&sub);
1600   
1601   return TRUE;
1602 }
1603
1604 static dbus_bool_t
1605 write_array_of_int32 (DataBlock      *block,
1606                       DBusTypeWriter *writer)
1607 {
1608   dbus_int32_t v;
1609   DataBlockState saved;
1610   DBusTypeWriter sub;
1611
1612   data_block_save (block, &saved);
1613   
1614   if (!_dbus_type_writer_recurse_array (writer,
1615                                         DBUS_TYPE_INT32_AS_STRING,
1616                                         &sub))
1617     return FALSE;
1618
1619   v = SAMPLE_INT32_ALTERNATE;
1620   if (!_dbus_type_writer_write_basic (&sub,
1621                                       DBUS_TYPE_INT32,
1622                                       &v))
1623     {
1624       data_block_restore (block, &saved);
1625       return FALSE;
1626     }
1627
1628   v = SAMPLE_INT32;
1629   if (!_dbus_type_writer_write_basic (&sub,
1630                                       DBUS_TYPE_INT32,
1631                                       &v))
1632     {
1633       data_block_restore (block, &saved);
1634       return FALSE;
1635     }
1636
1637   v = SAMPLE_INT32;
1638   if (!_dbus_type_writer_write_basic (&sub,
1639                                       DBUS_TYPE_INT32,
1640                                       &v))
1641     {
1642       data_block_restore (block, &saved);
1643       return FALSE;
1644     }
1645   
1646   if (!_dbus_type_writer_unrecurse (writer, &sub))
1647     {
1648       data_block_restore (block, &saved);
1649       return FALSE;
1650     }
1651   
1652   return TRUE;
1653 }
1654
1655 static dbus_bool_t
1656 read_array_of_int32 (DataBlock      *block,
1657                      DBusTypeReader *reader)
1658 {
1659   dbus_int32_t v;
1660   DBusTypeReader sub;
1661
1662   check_expected_type (reader, DBUS_TYPE_ARRAY);
1663   
1664   _dbus_type_reader_recurse (reader, &sub);
1665
1666   check_expected_type (&sub, DBUS_TYPE_INT32);
1667   
1668   _dbus_type_reader_read_basic (&sub,
1669                                 (dbus_int32_t*) &v);
1670
1671   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1672
1673   NEXT_EXPECTING_TRUE (&sub);
1674   check_expected_type (&sub, DBUS_TYPE_INT32);
1675   
1676   _dbus_type_reader_read_basic (&sub,
1677                                 (dbus_int32_t*) &v);
1678
1679   _dbus_assert (v == SAMPLE_INT32);
1680
1681   NEXT_EXPECTING_TRUE (&sub);
1682   check_expected_type (&sub, DBUS_TYPE_INT32);
1683   
1684   _dbus_type_reader_read_basic (&sub,
1685                                 (dbus_int32_t*) &v);
1686
1687   _dbus_assert (v == SAMPLE_INT32);
1688
1689   NEXT_EXPECTING_FALSE (&sub);
1690   
1691   return TRUE;
1692 }
1693
1694
1695 static dbus_bool_t
1696 write_array_of_int32_empty (DataBlock      *block,
1697                             DBusTypeWriter *writer)
1698 {
1699   DataBlockState saved;
1700   DBusTypeWriter sub;
1701
1702   data_block_save (block, &saved);
1703   
1704   if (!_dbus_type_writer_recurse_array (writer,
1705                                         DBUS_TYPE_INT32_AS_STRING,
1706                                         &sub))
1707     return FALSE;
1708   
1709   if (!_dbus_type_writer_unrecurse (writer, &sub))
1710     {
1711       data_block_restore (block, &saved);
1712       return FALSE;
1713     }
1714   
1715   return TRUE;
1716 }
1717
1718 static dbus_bool_t
1719 read_array_of_int32_empty (DataBlock      *block,
1720                            DBusTypeReader *reader)
1721 {
1722   check_expected_type (reader, DBUS_TYPE_ARRAY);
1723
1724   /* We are iterating over values not types. Thus we can't recurse
1725    * into the array
1726    */
1727   _dbus_assert (_dbus_type_reader_array_is_empty (reader));
1728   
1729   return TRUE;
1730 }
1731
1732 static dbus_bool_t
1733 write_array_of_array_of_int32 (DataBlock      *block,
1734                                DBusTypeWriter *writer)
1735 {
1736   DataBlockState saved;
1737   DBusTypeWriter sub;
1738
1739   data_block_save (block, &saved);
1740   
1741   if (!_dbus_type_writer_recurse_array (writer,
1742                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1743                                         &sub))
1744     return FALSE;
1745
1746   if (!write_array_of_int32 (block, &sub))
1747     {
1748       data_block_restore (block, &saved);
1749       return FALSE;
1750     }
1751
1752   if (!write_array_of_int32 (block, &sub))
1753     {
1754       data_block_restore (block, &saved);
1755       return FALSE;
1756     }
1757
1758   if (!write_array_of_int32_empty (block, &sub))
1759     {
1760       data_block_restore (block, &saved);
1761       return FALSE;
1762     }
1763   
1764   if (!write_array_of_int32 (block, &sub))
1765     {
1766       data_block_restore (block, &saved);
1767       return FALSE;
1768     }
1769   
1770   if (!_dbus_type_writer_unrecurse (writer, &sub))
1771     {
1772       data_block_restore (block, &saved);
1773       return FALSE;
1774     }
1775   
1776   return TRUE;
1777 }
1778
1779 static dbus_bool_t
1780 read_array_of_array_of_int32 (DataBlock      *block,
1781                               DBusTypeReader *reader)
1782 {
1783   DBusTypeReader sub;
1784   
1785   check_expected_type (reader, DBUS_TYPE_ARRAY);
1786   
1787   _dbus_type_reader_recurse (reader, &sub);
1788
1789   if (!read_array_of_int32 (block, &sub))
1790     return FALSE;
1791
1792   NEXT_EXPECTING_TRUE (&sub);
1793   if (!read_array_of_int32 (block, &sub))
1794     return FALSE;
1795
1796   NEXT_EXPECTING_TRUE (&sub);
1797   if (!read_array_of_int32_empty (block, &sub))
1798     return FALSE;
1799   
1800   NEXT_EXPECTING_TRUE (&sub);
1801   if (!read_array_of_int32 (block, &sub))
1802     return FALSE;
1803
1804   NEXT_EXPECTING_FALSE (&sub);
1805   
1806   return TRUE;
1807 }
1808
1809
1810 static dbus_bool_t
1811 write_array_of_array_of_int32_empty (DataBlock      *block,
1812                                      DBusTypeWriter *writer)
1813 {
1814   DataBlockState saved;
1815   DBusTypeWriter sub;
1816
1817   data_block_save (block, &saved);
1818   
1819   if (!_dbus_type_writer_recurse_array (writer,
1820                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1821                                         &sub))
1822     return FALSE;
1823
1824   if (!_dbus_type_writer_unrecurse (writer, &sub))
1825     {
1826       data_block_restore (block, &saved);
1827       return FALSE;
1828     }
1829   
1830   return TRUE;
1831 }
1832
1833 static dbus_bool_t
1834 read_array_of_array_of_int32_empty (DataBlock      *block,
1835                                     DBusTypeReader *reader)
1836 {  
1837   check_expected_type (reader, DBUS_TYPE_ARRAY);
1838
1839   /* We are iterating over values, not types. Thus
1840    * we can't recurse in here.
1841    */
1842   
1843   _dbus_assert (_dbus_type_reader_array_is_empty (reader));
1844   
1845   return TRUE;
1846 }
1847
1848 static dbus_bool_t
1849 write_array_of_array_of_array_of_int32 (DataBlock      *block,
1850                                         DBusTypeWriter *writer)
1851 {
1852   DataBlockState saved;
1853   DBusTypeWriter sub;
1854
1855   data_block_save (block, &saved);
1856   
1857   if (!_dbus_type_writer_recurse_array (writer,
1858                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1859                                         &sub))
1860     return FALSE;
1861
1862   if (!write_array_of_array_of_int32 (block, &sub))
1863     {
1864       data_block_restore (block, &saved);
1865       return FALSE;
1866     }
1867
1868   if (!write_array_of_array_of_int32 (block, &sub))
1869     {
1870       data_block_restore (block, &saved);
1871       return FALSE;
1872     }
1873
1874   if (!write_array_of_array_of_int32_empty (block, &sub))
1875     {
1876       data_block_restore (block, &saved);
1877       return FALSE;
1878     }
1879   
1880   if (!_dbus_type_writer_unrecurse (writer, &sub))
1881     {
1882       data_block_restore (block, &saved);
1883       return FALSE;
1884     }
1885   
1886   return TRUE;
1887 }
1888
1889 static dbus_bool_t
1890 read_array_of_array_of_array_of_int32 (DataBlock      *block,
1891                                        DBusTypeReader *reader)
1892 {
1893   DBusTypeReader sub;
1894   
1895   check_expected_type (reader, DBUS_TYPE_ARRAY);
1896   
1897   _dbus_type_reader_recurse (reader, &sub);
1898
1899   if (!read_array_of_array_of_int32 (block, &sub))
1900     return FALSE;
1901
1902   NEXT_EXPECTING_TRUE (&sub);
1903   if (!read_array_of_array_of_int32 (block, &sub))
1904     return FALSE;
1905
1906   NEXT_EXPECTING_TRUE (&sub);
1907   if (!read_array_of_array_of_int32_empty (block, &sub))
1908     return FALSE;
1909
1910   NEXT_EXPECTING_FALSE (&sub);
1911   
1912   return TRUE;
1913 }
1914
1915 static dbus_bool_t
1916 write_struct_of_array_of_int32 (DataBlock      *block,
1917                                 DBusTypeWriter *writer)
1918 {
1919   DataBlockState saved;
1920   DBusTypeWriter sub;
1921
1922   data_block_save (block, &saved);
1923   
1924   if (!_dbus_type_writer_recurse_struct (writer,
1925                                          &sub))
1926     return FALSE;
1927
1928   if (!write_array_of_int32 (block, &sub))
1929     {
1930       data_block_restore (block, &saved);
1931       return FALSE;
1932     }
1933
1934   if (!write_array_of_int32_empty (block, &sub))
1935     {
1936       data_block_restore (block, &saved);
1937       return FALSE;
1938     }
1939       
1940   if (!_dbus_type_writer_unrecurse (writer, &sub))
1941     {
1942       data_block_restore (block, &saved);
1943       return FALSE;
1944     }
1945   
1946   return TRUE;
1947 }
1948
1949 static dbus_bool_t
1950 read_struct_of_array_of_int32 (DataBlock      *block,
1951                                DBusTypeReader *reader)
1952 {
1953   DBusTypeReader sub;
1954
1955   check_expected_type (reader, DBUS_TYPE_STRUCT);
1956   
1957   _dbus_type_reader_recurse (reader, &sub);
1958
1959   check_expected_type (&sub, DBUS_TYPE_ARRAY);
1960
1961   if (!read_array_of_int32 (block, &sub))
1962     return FALSE;
1963
1964   NEXT_EXPECTING_TRUE (&sub);
1965   if (!read_array_of_int32_empty (block, &sub))
1966     return FALSE;
1967   
1968   NEXT_EXPECTING_FALSE (&sub);
1969   
1970   return TRUE;
1971 }
1972
1973 static dbus_bool_t
1974 write_struct_of_struct_of_array_of_int32 (DataBlock      *block,
1975                                           DBusTypeWriter *writer)
1976 {
1977   DataBlockState saved;
1978   DBusTypeWriter sub;
1979
1980   data_block_save (block, &saved);
1981   
1982   if (!_dbus_type_writer_recurse_struct (writer,
1983                                          &sub))
1984     return FALSE;
1985
1986   if (!write_struct_of_array_of_int32 (block, &sub))
1987     {
1988       data_block_restore (block, &saved);
1989       return FALSE;
1990     }
1991   if (!write_struct_of_array_of_int32 (block, &sub))
1992     {
1993       data_block_restore (block, &saved);
1994       return FALSE;
1995     }
1996   if (!write_struct_of_array_of_int32 (block, &sub))
1997     {
1998       data_block_restore (block, &saved);
1999       return FALSE;
2000     }
2001
2002   if (!_dbus_type_writer_unrecurse (writer, &sub))
2003     {
2004       data_block_restore (block, &saved);
2005       return FALSE;
2006     }
2007   
2008   return TRUE;
2009 }
2010
2011 static dbus_bool_t
2012 read_struct_of_struct_of_array_of_int32 (DataBlock      *block,
2013                                          DBusTypeReader *reader)
2014 {
2015   DBusTypeReader sub;
2016   
2017   check_expected_type (reader, DBUS_TYPE_STRUCT);
2018   
2019   _dbus_type_reader_recurse (reader, &sub);
2020
2021   if (!read_struct_of_array_of_int32 (block, &sub))
2022     return FALSE;
2023
2024   NEXT_EXPECTING_TRUE (&sub);
2025   if (!read_struct_of_array_of_int32 (block, &sub))
2026     return FALSE;
2027
2028   NEXT_EXPECTING_TRUE (&sub);
2029   if (!read_struct_of_array_of_int32 (block, &sub))
2030     return FALSE;
2031   
2032   NEXT_EXPECTING_FALSE (&sub);
2033   
2034   return TRUE;
2035 }
2036
2037 static dbus_bool_t
2038 write_array_of_struct_of_int32 (DataBlock      *block,
2039                                 DBusTypeWriter *writer)
2040 {
2041   DataBlockState saved;
2042   DBusTypeWriter sub;
2043
2044   data_block_save (block, &saved);
2045
2046   if (!_dbus_type_writer_recurse_array (writer,
2047                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2048                                         DBUS_TYPE_INT32_AS_STRING
2049                                         DBUS_TYPE_INT32_AS_STRING
2050                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2051                                         &sub))
2052     return FALSE;
2053
2054   if (!write_struct_of_int32 (block, &sub))
2055     {
2056       data_block_restore (block, &saved);
2057       return FALSE;
2058     }
2059
2060   if (!write_struct_of_int32 (block, &sub))
2061     {
2062       data_block_restore (block, &saved);
2063       return FALSE;
2064     }
2065
2066   if (!write_struct_of_int32 (block, &sub))
2067     {
2068       data_block_restore (block, &saved);
2069       return FALSE;
2070     }
2071   
2072   if (!_dbus_type_writer_unrecurse (writer, &sub))
2073     {
2074       data_block_restore (block, &saved);
2075       return FALSE;
2076     }
2077   
2078   return TRUE;
2079 }
2080
2081 static dbus_bool_t
2082 read_array_of_struct_of_int32 (DataBlock      *block,
2083                                DBusTypeReader *reader)
2084 {
2085   DBusTypeReader sub;
2086
2087   check_expected_type (reader, DBUS_TYPE_ARRAY);
2088   
2089   _dbus_type_reader_recurse (reader, &sub);
2090
2091   check_expected_type (&sub, DBUS_TYPE_STRUCT);
2092
2093   if (!read_struct_of_int32 (block, &sub))
2094     return FALSE;
2095   
2096   NEXT_EXPECTING_TRUE (&sub);
2097
2098   if (!read_struct_of_int32 (block, &sub))
2099     return FALSE;
2100   
2101   NEXT_EXPECTING_TRUE (&sub);
2102
2103   if (!read_struct_of_int32 (block, &sub))
2104     return FALSE;
2105   
2106   NEXT_EXPECTING_FALSE (&sub);
2107   
2108   return TRUE;
2109 }
2110
2111
2112 static dbus_bool_t
2113 write_array_of_array_of_struct_of_int32 (DataBlock      *block,
2114                                          DBusTypeWriter *writer)
2115 {
2116   DataBlockState saved;
2117   DBusTypeWriter sub;
2118
2119   data_block_save (block, &saved);
2120
2121   if (!_dbus_type_writer_recurse_array (writer,
2122                                         DBUS_TYPE_ARRAY_AS_STRING
2123                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2124                                         DBUS_TYPE_INT32_AS_STRING
2125                                         DBUS_TYPE_INT32_AS_STRING
2126                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2127                                         &sub))
2128     return FALSE;
2129
2130   if (!write_array_of_struct_of_int32 (block, &sub))
2131     {
2132       data_block_restore (block, &saved);
2133       return FALSE;
2134     }
2135
2136   if (!write_array_of_struct_of_int32 (block, &sub))
2137     {
2138       data_block_restore (block, &saved);
2139       return FALSE;
2140     }
2141
2142   if (!write_array_of_struct_of_int32 (block, &sub))
2143     {
2144       data_block_restore (block, &saved);
2145       return FALSE;
2146     }
2147   
2148   if (!_dbus_type_writer_unrecurse (writer, &sub))
2149     {
2150       data_block_restore (block, &saved);
2151       return FALSE;
2152     }
2153   
2154   return TRUE;
2155 }
2156
2157 static dbus_bool_t
2158 read_array_of_array_of_struct_of_int32 (DataBlock      *block,
2159                                         DBusTypeReader *reader)
2160 {
2161   DBusTypeReader sub;
2162
2163   check_expected_type (reader, DBUS_TYPE_ARRAY);
2164   
2165   _dbus_type_reader_recurse (reader, &sub);
2166
2167   check_expected_type (&sub, DBUS_TYPE_ARRAY);
2168
2169   if (!read_array_of_struct_of_int32 (block, &sub))
2170     return FALSE;
2171   
2172   NEXT_EXPECTING_TRUE (&sub);
2173
2174   if (!read_array_of_struct_of_int32 (block, &sub))
2175     return FALSE;
2176   
2177   NEXT_EXPECTING_TRUE (&sub);
2178
2179   if (!read_array_of_struct_of_int32 (block, &sub))
2180     return FALSE;
2181   
2182   NEXT_EXPECTING_FALSE (&sub);
2183   
2184   return TRUE;
2185 }
2186
2187 static dbus_bool_t
2188 write_struct_of_array_of_struct_of_int32 (DataBlock      *block,
2189                                           DBusTypeWriter *writer)
2190 {
2191   DataBlockState saved;
2192   DBusTypeWriter sub;
2193
2194   data_block_save (block, &saved);
2195   
2196   if (!_dbus_type_writer_recurse_struct (writer,
2197                                          &sub))
2198     return FALSE;
2199
2200   if (!write_array_of_struct_of_int32 (block, &sub))
2201     {
2202       data_block_restore (block, &saved);
2203       return FALSE;
2204     }
2205   if (!write_array_of_struct_of_int32 (block, &sub))
2206     {
2207       data_block_restore (block, &saved);
2208       return FALSE;
2209     }
2210   if (!write_array_of_struct_of_int32 (block, &sub))
2211     {
2212       data_block_restore (block, &saved);
2213       return FALSE;
2214     }
2215
2216   if (!_dbus_type_writer_unrecurse (writer, &sub))
2217     {
2218       data_block_restore (block, &saved);
2219       return FALSE;
2220     }
2221   
2222   return TRUE;
2223 }
2224
2225 static dbus_bool_t
2226 read_struct_of_array_of_struct_of_int32 (DataBlock      *block,
2227                                          DBusTypeReader *reader)
2228 {
2229   DBusTypeReader sub;
2230   
2231   check_expected_type (reader, DBUS_TYPE_STRUCT);
2232   
2233   _dbus_type_reader_recurse (reader, &sub);
2234   
2235   if (!read_array_of_struct_of_int32 (block, &sub))
2236     return FALSE;
2237
2238   NEXT_EXPECTING_TRUE (&sub);
2239   if (!read_array_of_struct_of_int32 (block, &sub))
2240     return FALSE;
2241
2242   NEXT_EXPECTING_TRUE (&sub);
2243   if (!read_array_of_struct_of_int32 (block, &sub))
2244     return FALSE;
2245   
2246   NEXT_EXPECTING_FALSE (&sub);
2247   
2248   return TRUE;
2249 }
2250
2251 static dbus_bool_t
2252 write_array_of_struct_of_array_of_int32 (DataBlock      *block,
2253                                          DBusTypeWriter *writer)
2254 {
2255   DataBlockState saved;
2256   DBusTypeWriter sub;
2257
2258   data_block_save (block, &saved);
2259
2260   if (!_dbus_type_writer_recurse_array (writer,
2261                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2262                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING
2263                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING
2264                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2265                                         &sub))
2266     return FALSE;
2267
2268   if (!write_struct_of_array_of_int32 (block, &sub))
2269     {
2270       data_block_restore (block, &saved);
2271       return FALSE;
2272     }
2273
2274   if (!write_struct_of_array_of_int32 (block, &sub))
2275     {
2276       data_block_restore (block, &saved);
2277       return FALSE;
2278     }
2279
2280   if (!write_struct_of_array_of_int32 (block, &sub))
2281     {
2282       data_block_restore (block, &saved);
2283       return FALSE;
2284     }
2285   
2286   if (!_dbus_type_writer_unrecurse (writer, &sub))
2287     {
2288       data_block_restore (block, &saved);
2289       return FALSE;
2290     }
2291   
2292   return TRUE;
2293 }
2294
2295 static dbus_bool_t
2296 read_array_of_struct_of_array_of_int32 (DataBlock      *block,
2297                                         DBusTypeReader *reader)
2298 {
2299   DBusTypeReader sub;
2300
2301   check_expected_type (reader, DBUS_TYPE_ARRAY);
2302   
2303   _dbus_type_reader_recurse (reader, &sub);
2304
2305   check_expected_type (&sub, DBUS_TYPE_STRUCT);
2306
2307   if (!read_struct_of_array_of_int32 (block, &sub))
2308     return FALSE;
2309   
2310   NEXT_EXPECTING_TRUE (&sub);
2311
2312   if (!read_struct_of_array_of_int32 (block, &sub))
2313     return FALSE;
2314   
2315   NEXT_EXPECTING_TRUE (&sub);
2316
2317   if (!read_struct_of_array_of_int32 (block, &sub))
2318     return FALSE;
2319   
2320   NEXT_EXPECTING_FALSE (&sub);
2321   
2322   return TRUE;
2323 }
2324
2325 typedef enum {
2326   ITEM_INVALID = -1,
2327
2328   ITEM_INT32 = 0,
2329
2330   ITEM_STRUCT_OF_INT32,
2331   ITEM_STRUCT_OF_STRUCTS,
2332   ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
2333
2334   ITEM_ARRAY_OF_INT32,
2335   ITEM_ARRAY_OF_INT32_EMPTY,
2336   ITEM_ARRAY_OF_ARRAY_OF_INT32,
2337   ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
2338   ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
2339
2340   ITEM_STRUCT_OF_ARRAY_OF_INT32,
2341   ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32,
2342
2343   ITEM_ARRAY_OF_STRUCT_OF_INT32,
2344   ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32,
2345
2346   ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32,
2347   ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32,
2348
2349   ITEM_LAST
2350 } WhichItem;
2351
2352
2353 typedef dbus_bool_t (* WriteItemFunc) (DataBlock      *block,
2354                                        DBusTypeWriter *writer);
2355 typedef dbus_bool_t (* ReadItemFunc)  (DataBlock      *block,
2356                                        DBusTypeReader *reader);
2357
2358 typedef struct
2359 {
2360   const char *desc;
2361   WhichItem which;
2362   WriteItemFunc write_item_func;
2363   ReadItemFunc read_item_func;
2364 } CheckMarshalItem;
2365
2366 static CheckMarshalItem items[] = {
2367   { "int32",
2368     ITEM_INT32, write_int32, read_int32 },
2369   { "struct with two int32",
2370     ITEM_STRUCT_OF_INT32, write_struct_of_int32, read_struct_of_int32 },
2371   { "struct with three structs of two int32",
2372     ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
2373   { "struct of two structs of three structs of two int32",
2374     ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
2375     write_struct_of_structs_of_structs,
2376     read_struct_of_structs_of_structs },
2377   { "array of int32",
2378     ITEM_ARRAY_OF_INT32, write_array_of_int32, read_array_of_int32 },
2379   { "empty array of int32",
2380     ITEM_ARRAY_OF_INT32_EMPTY, write_array_of_int32_empty, read_array_of_int32_empty },
2381   { "array of array of int32",
2382     ITEM_ARRAY_OF_ARRAY_OF_INT32,
2383     write_array_of_array_of_int32, read_array_of_array_of_int32 },
2384   { "empty array of array of int32",
2385     ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
2386     write_array_of_array_of_int32_empty, read_array_of_array_of_int32_empty },
2387   { "array of array of array of int32",
2388     ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
2389     write_array_of_array_of_array_of_int32, read_array_of_array_of_array_of_int32 },
2390   { "struct of array of int32",
2391     ITEM_STRUCT_OF_ARRAY_OF_INT32, write_struct_of_array_of_int32, read_struct_of_array_of_int32 },
2392   { "struct of struct of array of int32",
2393     ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32,
2394     write_struct_of_struct_of_array_of_int32, read_struct_of_struct_of_array_of_int32 },
2395   { "array of struct of int32",
2396     ITEM_ARRAY_OF_STRUCT_OF_INT32, write_array_of_struct_of_int32, read_array_of_struct_of_int32 },
2397   { "array of array of struct of int32",
2398     ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32,
2399     write_array_of_array_of_struct_of_int32, read_array_of_array_of_struct_of_int32 },
2400
2401   { "struct of array of struct of int32",
2402     ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32,
2403     write_struct_of_array_of_struct_of_int32, read_struct_of_array_of_struct_of_int32 },
2404   { "array of struct of array of int32",
2405     ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32,
2406     write_array_of_struct_of_array_of_int32, read_array_of_struct_of_array_of_int32 },
2407 };
2408
2409 typedef struct
2410 {
2411   /* Array of items from the above items[]; -1 terminated */
2412   int items[20];
2413 } TestRun;
2414
2415 static TestRun runs[] = {
2416   { { ITEM_INVALID } },
2417
2418   /* INT32 */
2419   { { ITEM_INT32, ITEM_INVALID } },
2420   { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
2421   { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
2422
2423   /* STRUCT_OF_INT32 */
2424   { { ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2425   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2426   { { ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2427   { { ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2428   { { ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2429
2430   /* STRUCT_OF_STRUCTS */
2431   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2432   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2433   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2434   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2435   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2436   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2437
2438   /* STRUCT_OF_STRUCTS_OF_STRUCTS */
2439   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2440   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2441   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2442   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2443   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2444   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2445
2446   /* ARRAY_OF_INT32 */
2447   { { ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2448   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2449   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2450   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2451   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2452   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2453   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2454   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2455   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2456   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2457
2458   /* ARRAY_OF_ARRAY_OF_INT32 */
2459   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2460   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2461   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2462   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2463   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2464   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2465   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2466   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2467   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2468   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2469
2470   /* ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32 */
2471   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2472   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2473   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2474   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2475   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2476   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2477   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2478   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2479   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2480   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2481
2482   /* STRUCT_OF_ARRAY_OF_INT32 */
2483   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2484   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2485   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2486   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2487   { { ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2488   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2489
2490   /* STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32 */
2491   { { ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2492   
2493   /* ARRAY_OF_STRUCT_OF_INT32 */
2494   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2495   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2496   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2497   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2498   { { ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2499   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2500
2501   /* ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32 */
2502   { { ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2503   
2504   /* STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32 */
2505   { { ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2506   
2507   /* ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32 */
2508   { { ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2509   
2510 };
2511
2512 static dbus_bool_t
2513 perform_one_run (DataBlock *block,
2514                  int        byte_order,
2515                  TestRun   *run)
2516 {
2517   DBusTypeReader reader;
2518   DBusTypeWriter writer;
2519   int i;
2520   DataBlockState saved;
2521   dbus_bool_t retval;
2522
2523   retval = FALSE;
2524
2525   {
2526     _dbus_verbose ("run byteorder %s items ",
2527                    byte_order == DBUS_LITTLE_ENDIAN ? "little" : "big");
2528     i = 0;
2529     while (run->items[i] != ITEM_INVALID)
2530       {
2531         CheckMarshalItem *item = &items[run->items[i]];
2532         
2533         _dbus_verbose ("%s ", item->desc);
2534         ++i;
2535       }
2536     _dbus_verbose (" = %d items\n", i);
2537   }
2538   
2539   data_block_save (block, &saved);
2540   
2541   data_block_init_reader_writer (block, 
2542                                  byte_order,
2543                                  &reader, &writer);
2544
2545   i = 0;
2546   while (run->items[i] != ITEM_INVALID)
2547     {
2548       CheckMarshalItem *item = &items[run->items[i]];
2549
2550       _dbus_verbose (">>writing %s\n", item->desc);
2551       
2552       if (!(* item->write_item_func) (block, &writer))
2553         goto out;
2554       ++i;
2555     }
2556
2557   i = 0;
2558   while (run->items[i] != ITEM_INVALID)
2559     {
2560       CheckMarshalItem *item = &items[run->items[i]];
2561
2562       _dbus_verbose (">>data for reading %s\n", item->desc);
2563       
2564       _dbus_verbose_bytes_of_string (reader.type_str, 0,
2565                                      _dbus_string_get_length (reader.type_str));
2566       _dbus_verbose_bytes_of_string (reader.value_str, 0,
2567                                      _dbus_string_get_length (reader.value_str));
2568       
2569       _dbus_verbose (">>reading %s\n", item->desc);
2570       
2571       if (!(* item->read_item_func) (block, &reader))
2572         goto out;
2573
2574       _dbus_type_reader_next (&reader);
2575       
2576       ++i;
2577     }
2578   
2579   retval = TRUE;
2580   
2581  out:
2582   data_block_restore (block, &saved);
2583   return retval;
2584 }
2585
2586 static dbus_bool_t
2587 perform_all_runs (int byte_order,
2588                   int initial_offset)
2589 {
2590   int i;
2591   DataBlock block;
2592   dbus_bool_t retval;
2593
2594   retval = FALSE;
2595   
2596   if (!data_block_init (&block))
2597     return FALSE;
2598
2599   if (!_dbus_string_lengthen (&block.signature, initial_offset))
2600     goto out;
2601   
2602   if (!_dbus_string_lengthen (&block.body, initial_offset))
2603     goto out;
2604   
2605   i = 0;
2606   while (i < _DBUS_N_ELEMENTS (runs))
2607     {
2608       if (!perform_one_run (&block, byte_order, &runs[i]))
2609         goto out;
2610       
2611       ++i;
2612     }
2613
2614   retval = TRUE;
2615   
2616  out:
2617   data_block_free (&block);
2618   
2619   return retval;
2620 }
2621
2622 static dbus_bool_t
2623 perform_all_items (int byte_order,
2624                    int initial_offset)
2625 {
2626   int i;
2627   DataBlock block;
2628   dbus_bool_t retval;
2629   TestRun run;
2630
2631   retval = FALSE;
2632   
2633   if (!data_block_init (&block))
2634     return FALSE;
2635
2636
2637   if (!_dbus_string_lengthen (&block.signature, initial_offset))
2638     goto out;
2639   
2640   if (!_dbus_string_lengthen (&block.body, initial_offset))
2641     goto out;
2642
2643   /* Create a run containing all the items */
2644   i = 0;
2645   while (i < _DBUS_N_ELEMENTS (items))
2646     {
2647       _dbus_assert (i == items[i].which);
2648       
2649       run.items[i] = items[i].which;
2650       
2651       ++i;
2652     }
2653   
2654   run.items[i] = ITEM_INVALID;
2655
2656   if (!perform_one_run (&block, byte_order, &run))
2657     goto out;  
2658   
2659   retval = TRUE;
2660   
2661  out:
2662   data_block_free (&block);
2663   
2664   return retval;
2665 }
2666
2667 static dbus_bool_t
2668 recursive_marshal_test_iteration (void *data)
2669 {
2670   int i;
2671
2672   i = 0;
2673   while (i < 18)
2674     {
2675       if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
2676         return FALSE;
2677       if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
2678         return FALSE;
2679       if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
2680         return FALSE;
2681       if (!perform_all_items (DBUS_BIG_ENDIAN, i))
2682         return FALSE;
2683       
2684       ++i;
2685     }
2686
2687   return TRUE;
2688 }
2689
2690 typedef struct TestTypeNode               TestTypeNode;
2691 typedef struct TestTypeNodeClass          TestTypeNodeClass;
2692 typedef struct TestTypeNodeContainer      TestTypeNodeContainer;
2693 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
2694
2695 struct TestTypeNode
2696 {
2697   const TestTypeNodeClass *klass;
2698 };
2699
2700 struct TestTypeNodeContainer
2701 {
2702   TestTypeNode base;
2703   DBusList    *children;
2704 };
2705
2706 struct TestTypeNodeClass
2707 {
2708   int typecode;
2709
2710   int instance_size;
2711   
2712   dbus_bool_t   (* construct)     (TestTypeNode   *node);
2713   void          (* destroy)       (TestTypeNode   *node);
2714   
2715   dbus_bool_t (* write_value)     (TestTypeNode   *node,
2716                                    DataBlock      *block,
2717                                    DBusTypeWriter *writer,
2718                                    int             seed);
2719   dbus_bool_t (* read_value)      (TestTypeNode   *node,
2720                                    DataBlock      *block,
2721                                    DBusTypeReader *reader,
2722                                    int             seed);
2723   dbus_bool_t (* build_signature) (TestTypeNode   *node,
2724                                    DBusString     *str);
2725 };
2726
2727 struct TestTypeNodeContainerClass
2728 {
2729   TestTypeNodeClass base;
2730 };
2731
2732 static dbus_bool_t int32_write_value        (TestTypeNode   *node,
2733                                              DataBlock      *block,
2734                                              DBusTypeWriter *writer,
2735                                              int             seed);
2736 static dbus_bool_t int32_read_value         (TestTypeNode   *node,
2737                                              DataBlock      *block,
2738                                              DBusTypeReader *reader,
2739                                              int             seed);
2740 static dbus_bool_t struct_1_write_value     (TestTypeNode   *node,
2741                                              DataBlock      *block,
2742                                              DBusTypeWriter *writer,
2743                                              int             seed);
2744 static dbus_bool_t struct_1_read_value      (TestTypeNode   *node,
2745                                              DataBlock      *block,
2746                                              DBusTypeReader *reader,
2747                                              int             seed);
2748 static dbus_bool_t struct_1_build_signature (TestTypeNode   *node,
2749                                              DBusString     *str);
2750 static dbus_bool_t struct_2_write_value     (TestTypeNode   *node,
2751                                              DataBlock      *block,
2752                                              DBusTypeWriter *writer,
2753                                              int             seed);
2754 static dbus_bool_t struct_2_read_value      (TestTypeNode   *node,
2755                                              DataBlock      *block,
2756                                              DBusTypeReader *reader,
2757                                              int             seed);
2758 static dbus_bool_t struct_2_build_signature (TestTypeNode   *node,
2759                                              DBusString     *str);
2760 static dbus_bool_t array_build_signature    (TestTypeNode   *node,
2761                                              DBusString     *str);
2762 static dbus_bool_t array_1_write_value      (TestTypeNode   *node,
2763                                              DataBlock      *block,
2764                                              DBusTypeWriter *writer,
2765                                              int             seed);
2766 static dbus_bool_t array_1_read_value       (TestTypeNode   *node,
2767                                              DataBlock      *block,
2768                                              DBusTypeReader *reader,
2769                                              int             seed);
2770 static dbus_bool_t array_0_write_value      (TestTypeNode   *node,
2771                                              DataBlock      *block,
2772                                              DBusTypeWriter *writer,
2773                                              int             seed);
2774 static dbus_bool_t array_0_read_value       (TestTypeNode   *node,
2775                                              DataBlock      *block,
2776                                              DBusTypeReader *reader,
2777                                              int             seed);
2778 static dbus_bool_t array_2_write_value      (TestTypeNode   *node,
2779                                              DataBlock      *block,
2780                                              DBusTypeWriter *writer,
2781                                              int             seed);
2782 static dbus_bool_t array_2_read_value       (TestTypeNode   *node,
2783                                              DataBlock      *block,
2784                                              DBusTypeReader *reader,
2785                                              int             seed);
2786 static void        container_destroy        (TestTypeNode   *node);
2787
2788
2789
2790 static const TestTypeNodeClass int32_class = {
2791   DBUS_TYPE_INT32,
2792   sizeof (TestTypeNode),
2793   NULL,
2794   NULL,
2795   int32_write_value,
2796   int32_read_value,
2797   NULL
2798 };
2799
2800 static const TestTypeNodeClass uint32_class = {
2801   DBUS_TYPE_UINT32,
2802   sizeof (TestTypeNode),
2803   NULL,
2804   NULL,
2805   int32_write_value, /* recycle from int32 */
2806   int32_read_value,  /* recycle from int32 */
2807   NULL
2808 };
2809
2810 static const TestTypeNodeClass struct_1_class = {
2811   DBUS_TYPE_STRUCT,
2812   sizeof (TestTypeNodeContainer),
2813   NULL,
2814   container_destroy,
2815   struct_1_write_value,
2816   struct_1_read_value,
2817   struct_1_build_signature
2818 };
2819
2820 static const TestTypeNodeClass struct_2_class = {
2821   DBUS_TYPE_STRUCT,
2822   sizeof (TestTypeNodeContainer),
2823   NULL,
2824   container_destroy,
2825   struct_2_write_value,
2826   struct_2_read_value,
2827   struct_2_build_signature
2828 };
2829
2830 static const TestTypeNodeClass array_0_class = {
2831   DBUS_TYPE_ARRAY,
2832   sizeof (TestTypeNodeContainer),
2833   NULL,
2834   container_destroy,
2835   array_0_write_value,
2836   array_0_read_value,
2837   array_build_signature
2838 };
2839
2840 static const TestTypeNodeClass array_1_class = {
2841   DBUS_TYPE_ARRAY,
2842   sizeof (TestTypeNodeContainer),
2843   NULL,
2844   container_destroy,
2845   array_1_write_value,
2846   array_1_read_value,
2847   array_build_signature
2848 };
2849
2850 static const TestTypeNodeClass array_2_class = {
2851   DBUS_TYPE_ARRAY,
2852   sizeof (TestTypeNodeContainer),
2853   NULL,
2854   container_destroy,
2855   array_2_write_value,
2856   array_2_read_value,
2857   array_build_signature
2858 };
2859
2860 static const TestTypeNodeClass* const
2861 basic_nodes[] = {
2862   &int32_class,
2863   &uint32_class
2864 };
2865 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2866
2867 static const TestTypeNodeClass* const
2868 container_nodes[] = {
2869   &struct_1_class,
2870   &array_1_class,
2871   &struct_2_class,
2872   &array_0_class,
2873   &array_2_class
2874 };
2875 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2876
2877 static TestTypeNode*
2878 node_new (const TestTypeNodeClass *klass)
2879 {
2880   TestTypeNode *node;
2881
2882   node = dbus_malloc0 (klass->instance_size);
2883   if (node == NULL)
2884     return NULL;
2885
2886   node->klass = klass;
2887   
2888   if (klass->construct)
2889     {
2890       if (!(* klass->construct) (node))
2891         {
2892           dbus_free (node);
2893           return FALSE;
2894         }
2895     }
2896
2897   return node;
2898 }
2899
2900 static void
2901 node_destroy (TestTypeNode *node)
2902 {
2903   if (node->klass->destroy)
2904     (* node->klass->destroy) (node);
2905   dbus_free (node);
2906 }
2907
2908 static dbus_bool_t
2909 node_write_value (TestTypeNode   *node,
2910                   DataBlock      *block,
2911                   DBusTypeWriter *writer,
2912                   int             seed)
2913 {
2914   return (* node->klass->write_value) (node, block, writer, seed);
2915 }
2916
2917 static dbus_bool_t
2918 node_read_value (TestTypeNode   *node,
2919                  DataBlock      *block,
2920                  DBusTypeReader *reader,
2921                  int             seed)
2922 {
2923   return (* node->klass->read_value) (node, block, reader, seed);
2924 }
2925
2926 static dbus_bool_t
2927 node_build_signature (TestTypeNode *node,
2928                       DBusString   *str)
2929 {
2930   if (node->klass->build_signature)
2931     return (* node->klass->build_signature) (node, str);
2932   else
2933     return _dbus_string_append_byte (str, node->klass->typecode);
2934 }
2935
2936 static dbus_bool_t
2937 node_append_child (TestTypeNode *node,
2938                    TestTypeNode *child)
2939 {
2940   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2941
2942   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2943
2944   if (!_dbus_list_append (&container->children, child))
2945     _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 */
2946
2947   return TRUE;
2948 }
2949
2950 typedef struct
2951 {
2952   const DBusString   *signature;
2953   DataBlock          *block;
2954   int                 type_offset;
2955   int                 byte_order;
2956   TestTypeNode      **nodes;
2957   int                 n_nodes;
2958 } NodeIterationData;
2959
2960 static dbus_bool_t
2961 run_test_nodes_iteration (void *data)
2962 {
2963   NodeIterationData *nid = data;
2964   DBusTypeReader reader;
2965   DBusTypeWriter writer;
2966   int i;
2967
2968   /* Stuff to do:
2969    * 1. write the value
2970    * 2. strcmp-compare with the signature we built
2971    * 3. read the value
2972    * 4. type-iterate the signature and the value and see if they are the same type-wise
2973    */
2974   data_block_init_reader_writer (nid->block,
2975                                  nid->byte_order,
2976                                  &reader, &writer);
2977
2978   i = 0;
2979   while (i < nid->n_nodes)
2980     {
2981       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2982         return FALSE;
2983
2984       ++i;
2985     }
2986
2987   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2988                                      &nid->block->signature, nid->type_offset))
2989     {
2990       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2991                   _dbus_string_get_const_data (nid->signature),
2992                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2993                   nid->type_offset);
2994       _dbus_assert_not_reached ("wrong signature");
2995     }
2996
2997   i = 0;
2998   while (i < nid->n_nodes)
2999     {
3000       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
3001         return FALSE;
3002
3003       if (i + 1 == nid->n_nodes)
3004         NEXT_EXPECTING_FALSE (&reader);
3005       else
3006         NEXT_EXPECTING_TRUE (&reader);
3007
3008       ++i;
3009     }
3010
3011   /* FIXME type-iterate both signature and value */
3012   
3013   return TRUE;
3014 }
3015
3016 static void
3017 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
3018                                      int               n_nodes,
3019                                      const DBusString *signature,
3020                                      int               byte_order,
3021                                      int               initial_offset)
3022 {
3023   DataBlock block;
3024   NodeIterationData nid;
3025
3026   if (!data_block_init (&block))
3027     _dbus_assert_not_reached ("no memory");
3028
3029   if (!_dbus_string_lengthen (&block.signature, initial_offset))
3030     _dbus_assert_not_reached ("no memory");
3031   
3032   if (!_dbus_string_lengthen (&block.body, initial_offset))
3033     _dbus_assert_not_reached ("no memory");
3034
3035   nid.signature = signature;
3036   nid.block = &block;
3037   nid.type_offset = initial_offset;
3038   nid.nodes = nodes;
3039   nid.n_nodes = n_nodes;
3040   nid.byte_order = byte_order;
3041   
3042   _dbus_test_oom_handling ("running test node",
3043                            run_test_nodes_iteration,
3044                            &nid);
3045
3046   data_block_free (&block);
3047 }
3048
3049 static void
3050 run_test_nodes (TestTypeNode **nodes,
3051                 int            n_nodes)
3052 {
3053   int i;
3054   DBusString signature;
3055
3056   if (!_dbus_string_init (&signature))
3057     _dbus_assert_not_reached ("no memory");
3058
3059   i = 0;
3060   while (i < n_nodes)
3061     {
3062       if (! node_build_signature (nodes[i], &signature))
3063         _dbus_assert_not_reached ("no memory");
3064
3065       ++i;
3066     }
3067       
3068   _dbus_verbose (">>> test nodes with signature '%s'\n",
3069                  _dbus_string_get_const_data (&signature));
3070
3071   /* We do start offset 0 through 9, to get various alignment cases. Still this
3072    * obviously makes the test suite run 10x as slow.
3073    */
3074   i = 0;
3075   while (i < 10)
3076     {
3077       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
3078                                            DBUS_LITTLE_ENDIAN, i);
3079       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
3080                                            DBUS_BIG_ENDIAN, i);
3081       
3082       ++i;
3083     }
3084
3085   _dbus_string_free (&signature);
3086 }
3087
3088 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
3089
3090 static TestTypeNode*
3091 value_generator (int *ip)
3092 {
3093   int i = *ip;
3094   const TestTypeNodeClass *child_klass;
3095   const TestTypeNodeClass *container_klass;
3096   TestTypeNode *child;
3097   TestTypeNode *node;
3098
3099   _dbus_assert (i <= N_VALUES);
3100   
3101   if (i == N_VALUES)
3102     {
3103       return NULL;
3104     }
3105   else if (i < N_BASICS)
3106     {
3107       node = node_new (basic_nodes[i]);
3108     }
3109   else
3110     {      
3111       /* imagine an array:
3112        * container 0 of basic 0
3113        * container 0 of basic 1
3114        * container 0 of basic 2
3115        * container 1 of basic 0
3116        * container 1 of basic 1
3117        * container 1 of basic 2
3118        */
3119       i -= N_BASICS;
3120
3121       container_klass = container_nodes[i / N_BASICS];
3122       child_klass = basic_nodes[i % N_BASICS];
3123       
3124       node = node_new (container_klass);
3125       child = node_new (child_klass);
3126       
3127       node_append_child (node, child);
3128     }
3129   
3130   *ip += 1; /* increment the generator */
3131
3132   return node;
3133 }
3134
3135 static void
3136 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
3137                                       int                      n_nested)
3138 {
3139   TestTypeNode *root;
3140   TestTypeNode *container;
3141   TestTypeNode *child;
3142   int i;
3143
3144   root = node_new (container_klass);
3145   container = root;
3146   for (i = 1; i < n_nested; i++)
3147     {
3148       child = node_new (container_klass);
3149       node_append_child (container, child);
3150       container = child;
3151     }
3152
3153   /* container should now be the most-nested container */
3154   
3155   i = 0;
3156   while ((child = value_generator (&i)))
3157     {
3158       node_append_child (container, child);
3159       
3160       run_test_nodes (&root, 1);
3161
3162       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
3163       node_destroy (child);
3164     }
3165
3166   node_destroy (root);
3167 }
3168
3169 static void
3170 make_and_run_test_nodes (void)
3171 {
3172   int i, j, k, m;
3173   
3174   /* We try to do this in order of "complicatedness" so that test
3175    * failures tend to show up in the simplest test case that
3176    * demonstrates the failure.  There are also some tests that run
3177    * more than once for this reason, first while going through simple
3178    * cases, second while going through a broader range of complex
3179    * cases.
3180    */
3181   /* Each basic node. The basic nodes should include:
3182    *
3183    * - each fixed-size type (in such a way that it has different values each time,
3184    *                         so we can tell if we mix two of them up)
3185    * - strings of length 0-9
3186    * - object path
3187    * - signature
3188    */
3189   /* Each container node. The container nodes should include:
3190    *
3191    *  struct with 1 and 2 copies of the contained item
3192    *  array with 0, 1, 2 copies of the contained item
3193    *  variant
3194    */
3195   /*  Let a "value" be a basic node, or a container containing a single basic node.
3196    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
3197    *  When iterating through all values to make combinations, do the basic types
3198    *  first and the containers second.
3199    */
3200   /* Each item is shown with its number of iterations to complete so
3201    * we can keep a handle on this unit test
3202    */
3203
3204   /* FIXME test just an empty body, no types at all */
3205
3206   _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
3207                  N_VALUES);
3208   {
3209     TestTypeNode *node;
3210     i = 0;
3211     while ((node = value_generator (&i)))
3212       {
3213         run_test_nodes (&node, 1);
3214         
3215         node_destroy (node);
3216       }
3217   }
3218
3219   _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
3220   {
3221     TestTypeNode *nodes[N_VALUES];
3222
3223     i = 0;
3224     while ((nodes[i] = value_generator (&i)))
3225       ;
3226
3227     run_test_nodes (nodes, N_VALUES);
3228
3229     for (i = 0; i < N_VALUES; i++)
3230       node_destroy (nodes[i]);
3231   }
3232   
3233   _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
3234                  N_VALUES * N_VALUES * 2);
3235   {
3236     TestTypeNode *nodes[2];
3237
3238     i = 0;
3239     while ((nodes[0] = value_generator (&i)))
3240       {
3241         j = 0;
3242         while ((nodes[1] = value_generator (&j)))
3243           {
3244             run_test_nodes (nodes, 2);
3245
3246             node_destroy (nodes[1]);
3247           }
3248
3249         node_destroy (nodes[0]);
3250       }
3251   }
3252   
3253   _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
3254                  N_CONTAINERS * N_VALUES);
3255   for (i = 0; i < N_CONTAINERS; i++)
3256     {
3257       const TestTypeNodeClass *container_klass = container_nodes[i];
3258
3259       make_and_run_values_inside_container (container_klass, 1);
3260     }
3261   
3262   _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
3263                  N_CONTAINERS * N_VALUES);
3264   for (i = 0; i < N_CONTAINERS; i++)
3265     {
3266       const TestTypeNodeClass *container_klass = container_nodes[i];
3267
3268       make_and_run_values_inside_container (container_klass, 2);
3269     }
3270
3271   _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
3272                  N_CONTAINERS * N_VALUES);
3273   for (i = 0; i < N_CONTAINERS; i++)
3274     {
3275       const TestTypeNodeClass *container_klass = container_nodes[i];
3276
3277       make_and_run_values_inside_container (container_klass, 3);
3278     }
3279   
3280   _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
3281                  N_VALUES * N_VALUES);
3282   {
3283     TestTypeNode *val1, *val2;
3284     TestTypeNode *node;
3285
3286     node = node_new (&struct_1_class);
3287
3288     i = 0;
3289     while ((val1 = value_generator (&i)))
3290       {
3291         j = 0;
3292         while ((val2 = value_generator (&j)))
3293           {
3294             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3295             
3296             node_append_child (node, val1);
3297             node_append_child (node, val2);
3298
3299             run_test_nodes (&node, 1);
3300             
3301             _dbus_list_clear (&container->children);
3302             node_destroy (val2);
3303           }
3304         node_destroy (val1);
3305       }
3306     node_destroy (node);
3307   }
3308   
3309   _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
3310   {
3311     TestTypeNode *node;
3312     TestTypeNode *child;
3313     
3314     node = node_new (&struct_1_class);
3315
3316     i = 0;
3317     while ((child = value_generator (&i)))
3318       node_append_child (node, child);
3319
3320     run_test_nodes (&node, 1);
3321     
3322     node_destroy (node);
3323   }
3324   
3325   _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
3326                  N_CONTAINERS * N_CONTAINERS * N_VALUES);
3327   for (i = 0; i < N_CONTAINERS; i++)
3328     {
3329       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
3330       TestTypeNode *outer_container = node_new (outer_container_klass);
3331       
3332       for (j = 0; j < N_CONTAINERS; j++)
3333         {
3334           TestTypeNode *child;
3335           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
3336           TestTypeNode *inner_container = node_new (inner_container_klass);
3337
3338           node_append_child (outer_container, inner_container);
3339               
3340           m = 0;
3341           while ((child = value_generator (&m)))
3342             {
3343               node_append_child (inner_container, child);
3344               
3345               run_test_nodes (&outer_container, 1);
3346
3347               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
3348               node_destroy (child);
3349             }
3350           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
3351           node_destroy (inner_container);
3352         }
3353       node_destroy (outer_container);
3354     }
3355   
3356   _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
3357                  N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
3358   for (i = 0; i < N_CONTAINERS; i++)
3359     {
3360       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
3361       TestTypeNode *outer_container = node_new (outer_container_klass);
3362       
3363       for (j = 0; j < N_CONTAINERS; j++)
3364         {
3365           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
3366           TestTypeNode *inner_container = node_new (inner_container_klass);
3367
3368           node_append_child (outer_container, inner_container);
3369           
3370           for (k = 0; k < N_CONTAINERS; k++)
3371             {
3372               TestTypeNode *child;
3373               const TestTypeNodeClass *center_container_klass = container_nodes[k];
3374               TestTypeNode *center_container = node_new (center_container_klass);              
3375
3376               node_append_child (inner_container, center_container);
3377               
3378               m = 0;
3379               while ((child = value_generator (&m)))
3380                 {
3381                   node_append_child (center_container, child);
3382                   
3383                   run_test_nodes (&outer_container, 1);
3384
3385                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
3386                   node_destroy (child);
3387                 }
3388               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
3389               node_destroy (center_container);
3390             }
3391           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
3392           node_destroy (inner_container);
3393         }
3394       node_destroy (outer_container);
3395     }
3396   
3397   _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
3398                  N_VALUES * N_VALUES * N_VALUES);
3399   {
3400     TestTypeNode *nodes[3];
3401
3402     i = 0;
3403     while ((nodes[0] = value_generator (&i)))
3404       {
3405         j = 0;
3406         while ((nodes[1] = value_generator (&j)))
3407           {
3408             k = 0;
3409             while ((nodes[2] = value_generator (&k)))
3410               {
3411                 run_test_nodes (nodes, 3);
3412                 
3413                 node_destroy (nodes[2]);
3414               }
3415             node_destroy (nodes[1]);
3416           }
3417         node_destroy (nodes[0]);
3418       }
3419   }
3420 }
3421
3422 dbus_bool_t _dbus_marshal_recursive_test (void);
3423
3424 dbus_bool_t
3425 _dbus_marshal_recursive_test (void)
3426 {
3427   /* The new comprehensive tests */
3428
3429 #if 1
3430   make_and_run_test_nodes ();
3431 #endif
3432   
3433 #if 0
3434   /* The old tests */
3435   _dbus_test_oom_handling ("recursive marshaling",
3436                            recursive_marshal_test_iteration,
3437                            NULL);  
3438 #endif
3439   
3440   return TRUE;
3441 }
3442
3443 #if 1
3444 int
3445 main (int argc, char **argv)
3446 {
3447   _dbus_marshal_recursive_test ();
3448
3449   return 0;
3450 }
3451 #endif /* main() */
3452
3453
3454 /*
3455  *
3456  *
3457  *         Implementations of each type node class
3458  *
3459  *
3460  *
3461  */
3462
3463 static dbus_int32_t
3464 int32_from_seed (int seed)
3465 {
3466   /* Generate an integer value that's predictable from seed.  We could
3467    * just use seed itself, but that would only ever touch one byte of
3468    * the int so would miss some kinds of bug.
3469    */
3470   dbus_int32_t v;
3471
3472   v = 42; /* just to quiet compiler afaik */
3473   switch (seed % 5)
3474     {
3475     case 0:
3476       v = SAMPLE_INT32;
3477       break;
3478     case 1:
3479       v = SAMPLE_INT32_ALTERNATE;
3480       break;
3481     case 2:
3482       v = -1;
3483       break;
3484     case 3:
3485       v = _DBUS_INT_MAX;
3486       break;
3487     case 4:
3488       v = 1;
3489       break;
3490     }
3491   
3492   if (seed > 1)
3493     v *= seed; /* wraps around eventually, which is fine */
3494
3495   return v;
3496 }
3497
3498 static dbus_bool_t
3499 int32_write_value (TestTypeNode   *node,
3500                    DataBlock      *block,
3501                    DBusTypeWriter *writer,
3502                    int             seed)
3503 {
3504   /* also used for uint32 */
3505   dbus_int32_t v;
3506
3507   v = int32_from_seed (seed);
3508   
3509   return _dbus_type_writer_write_basic (writer,
3510                                         node->klass->typecode,
3511                                         &v);
3512 }
3513
3514 static dbus_bool_t
3515 int32_read_value (TestTypeNode   *node,
3516                   DataBlock      *block,
3517                   DBusTypeReader *reader,
3518                   int             seed)
3519 {
3520   /* also used for uint32 */
3521   dbus_int32_t v;
3522
3523   check_expected_type (reader, node->klass->typecode);
3524   
3525   _dbus_type_reader_read_basic (reader,
3526                                 (dbus_int32_t*) &v);
3527   
3528   _dbus_assert (v == int32_from_seed (seed));
3529
3530   return TRUE;
3531 }
3532
3533 static dbus_bool_t
3534 struct_N_write_value (TestTypeNode   *node,
3535                       DataBlock      *block,
3536                       DBusTypeWriter *writer,
3537                       int             n_copies)
3538 {
3539   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3540   DataBlockState saved;
3541   DBusTypeWriter sub;
3542   int i;
3543
3544   _dbus_assert (container->children != NULL);
3545   
3546   data_block_save (block, &saved);
3547   
3548   if (!_dbus_type_writer_recurse_struct (writer,
3549                                          &sub))
3550     return FALSE;
3551
3552   i = 0;
3553   while (i < n_copies)
3554     {
3555       DBusList *link;
3556       
3557       link = _dbus_list_get_first_link (&container->children);
3558       while (link != NULL)
3559         {
3560           TestTypeNode *child = link->data;
3561           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3562
3563           if (!node_write_value (child, block, &sub, i))
3564             {
3565               data_block_restore (block, &saved);
3566               return FALSE;
3567             }
3568           
3569           link = next;
3570         }
3571
3572       ++i;
3573     }
3574   
3575   if (!_dbus_type_writer_unrecurse (writer, &sub))
3576     {
3577       data_block_restore (block, &saved);
3578       return FALSE;
3579     }
3580   
3581   return TRUE;
3582 }
3583
3584 static dbus_bool_t
3585 struct_N_read_value (TestTypeNode   *node,
3586                      DataBlock      *block,
3587                      DBusTypeReader *reader,
3588                      int             n_copies)
3589 {
3590   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3591   DBusTypeReader sub;
3592   int i;
3593   
3594   check_expected_type (reader, DBUS_TYPE_STRUCT);
3595   
3596   _dbus_type_reader_recurse (reader, &sub);
3597
3598   i = 0;
3599   while (i < n_copies)
3600     {
3601       DBusList *link;
3602       
3603       link = _dbus_list_get_first_link (&container->children);
3604       while (link != NULL)
3605         {
3606           TestTypeNode *child = link->data;
3607           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3608
3609           if (!node_read_value (child, block, &sub, i))
3610             return FALSE;
3611
3612           if (i == (n_copies - 1) && next == NULL)
3613             NEXT_EXPECTING_FALSE (&sub);
3614           else
3615             NEXT_EXPECTING_TRUE (&sub);
3616           
3617           link = next;
3618         }
3619
3620       ++i;
3621     }
3622   
3623   return TRUE;
3624 }
3625
3626 static dbus_bool_t
3627 struct_N_build_signature (TestTypeNode   *node,
3628                           DBusString     *str,
3629                           int             n_copies)
3630 {
3631   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3632   int i;
3633   int orig_len;
3634
3635   orig_len = _dbus_string_get_length (str);
3636
3637   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3638     goto oom;
3639   
3640   i = 0;
3641   while (i < n_copies)
3642     {
3643       DBusList *link;
3644       
3645       link = _dbus_list_get_first_link (&container->children);
3646       while (link != NULL)
3647         {
3648           TestTypeNode *child = link->data;
3649           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3650
3651           if (!node_build_signature (child, str))
3652             goto oom;
3653           
3654           link = next;
3655         }
3656
3657       ++i;
3658     }
3659
3660   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3661     goto oom;
3662   
3663   return TRUE;
3664   
3665  oom:
3666   _dbus_string_set_length (str, orig_len);
3667   return FALSE;
3668 }
3669
3670 static dbus_bool_t
3671 struct_1_write_value (TestTypeNode   *node,
3672                       DataBlock      *block,
3673                       DBusTypeWriter *writer,
3674                       int             seed)
3675 {
3676   return struct_N_write_value (node, block, writer, 1);
3677 }
3678
3679 static dbus_bool_t
3680 struct_1_read_value (TestTypeNode   *node,
3681                      DataBlock      *block,
3682                      DBusTypeReader *reader,
3683                      int             seed)
3684 {
3685   return struct_N_read_value (node, block, reader, 1);
3686 }
3687
3688 static dbus_bool_t
3689 struct_1_build_signature (TestTypeNode   *node,
3690                           DBusString     *str)
3691 {
3692   return struct_N_build_signature (node, str, 1);
3693 }
3694
3695
3696 static dbus_bool_t
3697 struct_2_write_value (TestTypeNode   *node,
3698                       DataBlock      *block,
3699                       DBusTypeWriter *writer,
3700                       int             seed)
3701 {
3702   return struct_N_write_value (node, block, writer, 2);
3703 }
3704
3705 static dbus_bool_t
3706 struct_2_read_value (TestTypeNode   *node,
3707                      DataBlock      *block,
3708                      DBusTypeReader *reader,
3709                      int             seed)
3710 {
3711   return struct_N_read_value (node, block, reader, 2);
3712 }
3713
3714 static dbus_bool_t
3715 struct_2_build_signature (TestTypeNode   *node,
3716                           DBusString     *str)
3717 {
3718   return struct_N_build_signature (node, str, 2);
3719 }
3720
3721 static dbus_bool_t
3722 array_N_write_value (TestTypeNode   *node,
3723                      DataBlock      *block,
3724                      DBusTypeWriter *writer,
3725                      int             n_copies)
3726 {
3727   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3728   DataBlockState saved;
3729   DBusTypeWriter sub;
3730   DBusString element_signature;
3731   int i;
3732
3733   _dbus_assert (container->children != NULL);
3734
3735   data_block_save (block, &saved);
3736   
3737   if (!_dbus_string_init (&element_signature))
3738     return FALSE;
3739
3740   if (!node_build_signature (_dbus_list_get_first (&container->children),
3741                              &element_signature))
3742     goto oom;
3743   
3744   if (!_dbus_type_writer_recurse_array (writer,
3745                                         _dbus_string_get_const_data (&element_signature),
3746                                         &sub))
3747     goto oom;
3748
3749   i = 0;
3750   while (i < n_copies)
3751     {
3752       DBusList *link;
3753       
3754       link = _dbus_list_get_first_link (&container->children);
3755       while (link != NULL)
3756         {
3757           TestTypeNode *child = link->data;
3758           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3759
3760           if (!node_write_value (child, block, &sub, i))
3761             goto oom;
3762           
3763           link = next;
3764         }
3765
3766       ++i;
3767     }
3768   
3769   if (!_dbus_type_writer_unrecurse (writer, &sub))
3770     goto oom;
3771   
3772   return TRUE;
3773
3774  oom:
3775   data_block_restore (block, &saved);
3776   _dbus_string_free (&element_signature);
3777   return FALSE;
3778 }
3779
3780 static dbus_bool_t
3781 array_N_read_value (TestTypeNode   *node,
3782                     DataBlock      *block,
3783                     DBusTypeReader *reader,
3784                     int             n_copies)
3785 {
3786   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3787   DBusTypeReader sub;
3788   int i;
3789   
3790   check_expected_type (reader, DBUS_TYPE_ARRAY);
3791
3792   if (n_copies > 0)
3793     {
3794       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3795       
3796       _dbus_type_reader_recurse (reader, &sub);
3797
3798       i = 0;
3799       while (i < n_copies)
3800         {
3801           DBusList *link;
3802           
3803           link = _dbus_list_get_first_link (&container->children);
3804           while (link != NULL)
3805             {
3806               TestTypeNode *child = link->data;
3807               DBusList *next = _dbus_list_get_next_link (&container->children, link);
3808               
3809               if (!node_read_value (child, block, &sub, i))
3810                 return FALSE;
3811               
3812               if (i == (n_copies - 1) && next == NULL)
3813                 NEXT_EXPECTING_FALSE (&sub);
3814               else
3815                 NEXT_EXPECTING_TRUE (&sub);
3816               
3817               link = next;
3818             }
3819           
3820           ++i;
3821         }
3822     }
3823   else
3824     {
3825       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3826     }
3827     
3828   return TRUE;
3829 }
3830
3831 static dbus_bool_t
3832 array_build_signature (TestTypeNode   *node,
3833                        DBusString     *str)
3834 {
3835   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3836   int orig_len;
3837   
3838   orig_len = _dbus_string_get_length (str);
3839
3840   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3841     goto oom;
3842
3843   if (!node_build_signature (_dbus_list_get_first (&container->children),
3844                              str))
3845     goto oom;
3846   
3847   return TRUE;
3848   
3849  oom:
3850   _dbus_string_set_length (str, orig_len);
3851   return FALSE;
3852 }
3853
3854 static dbus_bool_t
3855 array_0_write_value (TestTypeNode   *node,
3856                      DataBlock      *block,
3857                      DBusTypeWriter *writer,
3858                      int             seed)
3859 {
3860   return array_N_write_value (node, block, writer, 0);
3861 }
3862
3863 static dbus_bool_t
3864 array_0_read_value (TestTypeNode   *node,
3865                     DataBlock      *block,
3866                     DBusTypeReader *reader,
3867                     int             seed)
3868 {
3869   return array_N_read_value (node, block, reader, 0);
3870 }
3871
3872
3873 static dbus_bool_t
3874 array_1_write_value (TestTypeNode   *node,
3875                      DataBlock      *block,
3876                      DBusTypeWriter *writer,
3877                      int             seed)
3878 {
3879   return array_N_write_value (node, block, writer, 1);
3880 }
3881
3882 static dbus_bool_t
3883 array_1_read_value (TestTypeNode   *node,
3884                     DataBlock      *block,
3885                     DBusTypeReader *reader,
3886                        int          seed)
3887 {
3888   return array_N_read_value (node, block, reader, 1);
3889 }
3890
3891 static dbus_bool_t
3892 array_2_write_value (TestTypeNode   *node,
3893                      DataBlock      *block,
3894                      DBusTypeWriter *writer,
3895                      int             seed)
3896 {
3897   return array_N_write_value (node, block, writer, 2);
3898 }
3899
3900 static dbus_bool_t
3901 array_2_read_value (TestTypeNode   *node,
3902                     DataBlock      *block,
3903                     DBusTypeReader *reader,
3904                     int             seed)
3905 {
3906   return array_N_read_value (node, block, reader, 2);
3907 }
3908
3909 static void
3910 container_destroy (TestTypeNode *node)
3911 {
3912   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3913   DBusList *link;
3914   
3915   link = _dbus_list_get_first_link (&container->children);
3916   while (link != NULL)
3917     {
3918       TestTypeNode *child = link->data;
3919       DBusList *next = _dbus_list_get_next_link (&container->children, link);
3920
3921       node_destroy (child);
3922
3923       _dbus_list_free_link (link);
3924       
3925       link = next;
3926     }
3927 }
3928
3929 #endif /* DBUS_BUILD_TESTS */