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