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