values-only DBusTypeWriter
[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 1
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_marshal_read_basic (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 (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 (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_marshal_read_basic (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_marshal_read_basic (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_set_basic_fixed_length (DBusTypeReader *reader,
863                                int             current_type,
864                                const void     *value)
865 {
866   _dbus_marshal_set_basic ((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 readers may
877  * of course be invalidated if you set a variable-length type such as
878  * a string.
879  *
880  * The provided realign_root is the reader to start from when
881  * realigning the data that follows the newly-set value. The reader
882  * parameter must point to a value below the realign_root parameter.
883  * If the type being set is fixed-length, then realign_root may be
884  * #NULL. Only values reachable from realign_root will be realigned,
885  * so if your string contains other values you will need to deal with
886  * those somehow yourself. It is OK if realign_root is the same
887  * reader as the reader parameter, though if you aren't setting the
888  * root it may not be such a good idea.
889  *
890  * @todo DBusTypeReader currently takes "const" versions of the type
891  * and value strings, and this function modifies those strings by
892  * casting away the const, which is of course bad if we want to get
893  * picky. (To be truly clean you'd have an object which contained the
894  * type and value strings and set_basic would be a method on that
895  * object... this would also make DBusTypeReader the same thing as
896  * DBusTypeMark. But since DBusMessage is effectively that object for
897  * D-BUS it doesn't seem worth creating some random object.)
898  *
899  * @param reader reader indicating where to set a new value
900  * @param value address of the value to set
901  * @param realign_root realign from here
902  * @returns #FALSE if not enough memory
903  */
904 dbus_bool_t
905 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
906                              const void           *value,
907                              const DBusTypeReader *realign_root)
908 {
909   int current_type;
910   dbus_bool_t retval;
911
912   retval = FALSE;
913
914   current_type = _dbus_type_reader_get_current_type (reader);
915
916   _dbus_assert (_dbus_type_is_basic (current_type));
917
918   if (!_dbus_type_length_varies (current_type))
919     {
920       reader_set_basic_fixed_length (reader, current_type, value);
921       return TRUE;
922     }
923
924   _dbus_assert (realign_root != NULL);
925
926   /* In the harder case, we have to fix alignment after we insert.
927    * The basic strategy is as follows:
928    *
929    *  - pad a new string to have the same alignment as the
930    *    start of the current basic value
931    *  - write the new basic value
932    *  - copy from the original reader to the new string,
933    *    which will fix the alignment of types following
934    *    the new value
935    *    - this copy has to start at realign_root,
936    *      but not really write anything until it
937    *      passes the value being set
938    *    - as an optimization, we can stop copying
939    *      when the source and dest values are both
940    *      on an 8-boundary, since we know all following
941    *      padding and alignment will be identical
942    *  - copy the new string back to the original
943    *    string, replacing the relevant part of the
944    *    original string
945    */
946
947   /* FIXME I don't know how to implement this exactly, since
948    * DBusTypeWriter can't write children of a value without writing
949    * the entire parent value, and so we can't copy only the stuff
950    * following the new value.
951    *
952    * Suggestion is:
953    *  - add 'values only' mode to the writer (which essentially
954    *    just sets type_pos_is_expectation on the toplevel)
955    *  - add 'don't write for now' mode that can be toggled;
956    *  - implement a write_reader that uses those things to
957    *    realign
958    */
959
960   retval = TRUE;
961
962  out:
963
964   return retval;
965 }
966
967 /*
968  *
969  *
970  *         DBusTypeWriter
971  *
972  *
973  *
974  */
975
976 /**
977  * Initialize a write iterator, which is used to write out values in
978  * serialized D-BUS format.
979  *
980  * The type_pos passed in is expected to be inside an already-valid,
981  * though potentially empty, type signature. This means that the byte
982  * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
983  * other valid type. #DBusTypeWriter won't enforce that the signature
984  * is already valid (you can append the nul byte at the end if you
985  * like), but just be aware that you need the nul byte eventually and
986  * #DBusTypeWriter isn't going to write it for you.
987  *
988  * @param writer the writer to init
989  * @param byte_order the byte order to marshal into
990  * @param type_str the string to write typecodes into
991  * @param type_pos where to insert typecodes
992  * @param value_str the string to write values into
993  * @param value_pos where to insert values
994  *
995  */
996 void
997 _dbus_type_writer_init (DBusTypeWriter *writer,
998                         int             byte_order,
999                         DBusString     *type_str,
1000                         int             type_pos,
1001                         DBusString     *value_str,
1002                         int             value_pos)
1003 {
1004   writer->byte_order = byte_order;
1005   writer->type_str = type_str;
1006   writer->type_pos = type_pos;
1007   writer->value_str = value_str;
1008   writer->value_pos = value_pos;
1009   writer->container_type = DBUS_TYPE_INVALID;
1010   writer->type_pos_is_expectation = FALSE;
1011
1012 #if RECURSIVE_MARSHAL_TRACE
1013   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1014                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1015 #endif
1016 }
1017
1018 /**
1019  * Like _dbus_type_writer_init(), except the type string
1020  * passed in should correspond to an existing signature that
1021  * matches what you're going to write out. The writer will
1022  * check what you write vs. this existing signature.
1023  *
1024  * @param writer the writer to init
1025  * @param byte_order the byte order to marshal into
1026  * @param type_str the string with signature
1027  * @param type_pos start of signature
1028  * @param value_str the string to write values into
1029  * @param value_pos where to insert values
1030  *
1031  */
1032 void
1033 _dbus_type_writer_init_values_only (DBusTypeWriter   *writer,
1034                                     int               byte_order,
1035                                     const DBusString *type_str,
1036                                     int               type_pos,
1037                                     DBusString       *value_str,
1038                                     int               value_pos)
1039 {
1040   _dbus_type_writer_init (writer, byte_order,
1041                           (DBusString*)type_str, type_pos,
1042                           value_str, value_pos);
1043
1044   writer->type_pos_is_expectation = TRUE;
1045 }
1046
1047 static dbus_bool_t
1048 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1049                                            int             type,
1050                                            const void     *value)
1051 {
1052   return _dbus_marshal_write_basic (writer->value_str,
1053                                     writer->value_pos,
1054                                     type,
1055                                     value,
1056                                     writer->byte_order,
1057                                     &writer->value_pos);
1058 }
1059
1060 /* If our parent is an array, things are a little bit complicated.
1061  *
1062  * The parent must have a complete element type, such as
1063  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1064  * unclosed parens, or an "a" with no following type.
1065  *
1066  * To recurse, the only allowed operation is to recurse into the
1067  * first type in the element type. So for "i" you can't recurse, for
1068  * "ai" you can recurse into the array, for "(ii)" you can recurse
1069  * into the struct.
1070  *
1071  * If you recurse into the array for "ai", then you must specify
1072  * "i" for the element type of the array you recurse into.
1073  *
1074  * While inside an array at any level, we need to avoid writing to
1075  * type_str, since the type only appears once for the whole array,
1076  * it does not appear for each array element.
1077  *
1078  * While inside an array type_pos points to the expected next
1079  * typecode, rather than the next place we could write a typecode.
1080  */
1081 static void
1082 writer_recurse_init_and_check (DBusTypeWriter *writer,
1083                                int             container_type,
1084                                DBusTypeWriter *sub)
1085 {
1086   _dbus_type_writer_init (sub,
1087                           writer->byte_order,
1088                           writer->type_str,
1089                           writer->type_pos,
1090                           writer->value_str,
1091                           writer->value_pos);
1092
1093   sub->container_type = container_type;
1094
1095   if (writer->type_pos_is_expectation ||
1096       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
1097     sub->type_pos_is_expectation = TRUE;
1098   else
1099     sub->type_pos_is_expectation = FALSE;
1100
1101 #ifndef DBUS_DISABLE_CHECKS
1102   if (writer->type_pos_is_expectation)
1103     {
1104       int expected;
1105
1106       expected = first_type_in_signature (writer->type_str, writer->type_pos);
1107
1108       if (expected != sub->container_type)
1109         {
1110           _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
1111                       _dbus_type_to_string (sub->container_type),
1112                       _dbus_type_to_string (expected));
1113           _dbus_assert_not_reached ("bad array element or variant content written");
1114         }
1115     }
1116 #endif /* DBUS_DISABLE_CHECKS */
1117
1118 #if RECURSIVE_MARSHAL_TRACE
1119   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
1120                  writer,
1121                  _dbus_type_to_string (writer->container_type),
1122                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1123                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1124   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d\n",
1125                  sub,
1126                  _dbus_type_to_string (sub->container_type),
1127                  sub->type_pos, sub->value_pos,
1128                  sub->type_pos_is_expectation);
1129 #endif
1130 }
1131
1132 static dbus_bool_t
1133 write_or_verify_typecode (DBusTypeWriter *writer,
1134                           int             typecode)
1135 {
1136   /* A subwriter inside an array or variant will have type_pos
1137    * pointing to the expected typecode; a writer not inside an array
1138    * or variant has type_pos pointing to the next place to insert a
1139    * typecode.
1140    */
1141 #if RECURSIVE_MARSHAL_TRACE
1142   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
1143                  writer, writer->type_pos,
1144                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1145 #endif
1146
1147   if (writer->type_pos_is_expectation)
1148     {
1149 #ifndef DBUS_DISABLE_CHECKS
1150       {
1151         int expected;
1152
1153         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1154
1155         if (expected != typecode)
1156           {
1157             _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1158                         _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1159             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1160           }
1161       }
1162 #endif /* DBUS_DISABLE_CHECKS */
1163
1164       /* if immediately inside an array we'd always be appending an element,
1165        * so the expected type doesn't change; if inside a struct or something
1166        * below an array, we need to move through said struct or something.
1167        */
1168       if (writer->container_type != DBUS_TYPE_ARRAY)
1169         writer->type_pos += 1;
1170     }
1171   else
1172     {
1173       if (!_dbus_string_insert_byte (writer->type_str,
1174                                      writer->type_pos,
1175                                      typecode))
1176         return FALSE;
1177
1178       writer->type_pos += 1;
1179     }
1180
1181 #if RECURSIVE_MARSHAL_TRACE
1182   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1183                  writer, writer->type_pos,
1184                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1185 #endif
1186
1187   return TRUE;
1188 }
1189
1190 static dbus_bool_t
1191 writer_recurse_struct (DBusTypeWriter   *writer,
1192                        const DBusString *contained_type,
1193                        int               contained_type_start,
1194                        int               contained_type_len,
1195                        DBusTypeWriter   *sub)
1196 {
1197   /* FIXME right now contained_type is ignored; we could probably
1198    * almost trivially fix the code so if it's present we
1199    * write it out and then set type_pos_is_expectation
1200    */
1201
1202   /* Ensure that we'll be able to add alignment padding and the typecode */
1203   if (!_dbus_string_alloc_space (sub->value_str, 8))
1204     return FALSE;
1205
1206   if (!_dbus_string_alloc_space (sub->type_str, 1))
1207     return FALSE;
1208
1209   if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1210     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1211
1212   if (!_dbus_string_insert_bytes (sub->value_str,
1213                                   sub->value_pos,
1214                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1215                                   '\0'))
1216     _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1217   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1218
1219   return TRUE;
1220 }
1221
1222
1223 static dbus_bool_t
1224 writer_recurse_array (DBusTypeWriter   *writer,
1225                       const DBusString *contained_type,
1226                       int               contained_type_start,
1227                       int               contained_type_len,
1228                       DBusTypeWriter   *sub)
1229 {
1230   dbus_uint32_t value = 0;
1231   int alignment;
1232   int aligned;
1233
1234 #ifndef DBUS_DISABLE_CHECKS
1235   if (writer->container_type == DBUS_TYPE_ARRAY)
1236     {
1237       if (!_dbus_string_equal_substring (contained_type,
1238                                          contained_type_start,
1239                                          contained_type_len,
1240                                          writer->type_str,
1241                                          writer->u.array.element_type_pos + 1))
1242         {
1243           _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1244                       _dbus_string_get_const_data_len (contained_type,
1245                                                        contained_type_start,
1246                                                        contained_type_len));
1247           _dbus_assert_not_reached ("incompatible type for child array");
1248         }
1249     }
1250 #endif /* DBUS_DISABLE_CHECKS */
1251
1252   /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1253    * before array values
1254    */
1255   if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1256     return FALSE;
1257
1258   sub->type_pos += 1; /* move to point to the element type, since type_pos
1259                        * should be the expected type for further writes
1260                        */
1261   sub->u.array.element_type_pos = sub->type_pos;
1262
1263   if (!writer->type_pos_is_expectation)
1264     {
1265       /* sub is a toplevel/outermost array so we need to write the type data */
1266
1267       /* alloc space for array typecode, element signature */
1268       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1269         return FALSE;
1270
1271       if (!_dbus_string_insert_byte (writer->type_str,
1272                                      writer->type_pos,
1273                                      DBUS_TYPE_ARRAY))
1274         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1275
1276       if (!_dbus_string_copy_len (contained_type,
1277                                   contained_type_start, contained_type_len,
1278                                   sub->type_str,
1279                                   sub->u.array.element_type_pos))
1280         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1281     }
1282
1283   /* If the parent is an array, we hold type_pos pointing at the array element type;
1284    * otherwise advance it to reflect the array value we just recursed into
1285    */
1286   if (writer->container_type != DBUS_TYPE_ARRAY)
1287     writer->type_pos += 1 + contained_type_len;
1288   else
1289     _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1290
1291   /* Write the length */
1292   sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1293
1294   if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1295                                                   &value))
1296     _dbus_assert_not_reached ("should not have failed to insert array len");
1297
1298   _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1299
1300   /* Write alignment padding for array elements
1301    * Note that we write the padding *even for empty arrays*
1302    * to avoid wonky special cases
1303    */
1304   alignment = element_type_get_alignment (contained_type, contained_type_start);
1305
1306   aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1307   if (aligned != sub->value_pos)
1308     {
1309       if (!_dbus_string_insert_bytes (sub->value_str,
1310                                       sub->value_pos,
1311                                       aligned - sub->value_pos,
1312                                       '\0'))
1313         _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1314
1315       sub->value_pos = aligned;
1316     }
1317   sub->u.array.start_pos = sub->value_pos;
1318
1319   _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1320   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1321
1322 #if RECURSIVE_MARSHAL_TRACE
1323   _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1324                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0),
1325                  sub->u.array.start_pos, sub->u.array.len_pos);
1326 #endif
1327
1328   return TRUE;
1329 }
1330
1331 /* Variant value will normally have:
1332  *   1 byte signature length not including nul
1333  *   signature typecodes (nul terminated)
1334  *   padding to 8-boundary
1335  *   body according to signature
1336  *
1337  * The signature string can only have a single type
1338  * in it but that type may be complex/recursive.
1339  *
1340  * So a typical variant type with the integer 3 will have these
1341  * octets:
1342  *   0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1343  *
1344  * For an array of 4-byte types stuffed into variants, the padding to
1345  * 8-boundary is only the 1 byte that is required for the 4-boundary
1346  * anyhow for all array elements after the first one. And for single
1347  * variants in isolation, wasting a few bytes is hardly a big deal.
1348  *
1349  * The main world of hurt for writing out a variant is that the type
1350  * string is the same string as the value string. Which means
1351  * inserting to the type string will move the value_pos; and it means
1352  * that inserting to the type string could break type alignment.
1353  *
1354  * This type alignment issue is why the body of the variant is always
1355  * 8-aligned. Then we know that re-8-aligning the start of the body
1356  * will always correctly align the full contents of the variant type.
1357  */
1358 static dbus_bool_t
1359 writer_recurse_variant (DBusTypeWriter   *writer,
1360                         const DBusString *contained_type,
1361                         int               contained_type_start,
1362                         int               contained_type_len,
1363                         DBusTypeWriter   *sub)
1364 {
1365   /* Allocate space for the worst case, which is 1 byte sig
1366    * length, nul byte at end of sig, and 7 bytes padding to
1367    * 8-boundary.
1368    */
1369   if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1370     return FALSE;
1371
1372   /* write VARIANT typecode to the parent's type string */
1373   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1374     return FALSE;
1375
1376   if (!_dbus_string_insert_byte (sub->value_str,
1377                                  sub->value_pos,
1378                                  contained_type_len))
1379     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1380
1381   sub->value_pos += 1;
1382
1383   /* Here we switch over to the expected type sig we're about to write */
1384   sub->type_str = sub->value_str;
1385   sub->type_pos = sub->value_pos;
1386
1387   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
1388                               sub->value_str, sub->value_pos))
1389     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1390
1391   sub->value_pos += contained_type_len;
1392
1393   if (!_dbus_string_insert_byte (sub->value_str,
1394                                  sub->value_pos,
1395                                  DBUS_TYPE_INVALID))
1396     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1397
1398   sub->value_pos += 1;
1399
1400   if (!_dbus_string_insert_bytes (sub->value_str,
1401                                   sub->value_pos,
1402                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1403                                   '\0'))
1404     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1405   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1406
1407   return TRUE;
1408 }
1409
1410 static dbus_bool_t
1411 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
1412                                          int               container_type,
1413                                          const DBusString *contained_type,
1414                                          int               contained_type_start,
1415                                          int               contained_type_len,
1416                                          DBusTypeWriter   *sub)
1417 {
1418   writer_recurse_init_and_check (writer, container_type, sub);
1419
1420   switch (container_type)
1421     {
1422     case DBUS_TYPE_STRUCT:
1423       return writer_recurse_struct (writer,
1424                                     contained_type, contained_type_start, contained_type_len,
1425                                     sub);
1426       break;
1427     case DBUS_TYPE_ARRAY:
1428       return writer_recurse_array (writer,
1429                                    contained_type, contained_type_start, contained_type_len,
1430                                    sub);
1431       break;
1432     case DBUS_TYPE_VARIANT:
1433       return writer_recurse_variant (writer,
1434                                      contained_type, contained_type_start, contained_type_len,
1435                                      sub);
1436       break;
1437     default:
1438       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
1439       return FALSE;
1440       break;
1441     }
1442 }
1443
1444 dbus_bool_t
1445 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
1446                            int               container_type,
1447                            const DBusString *contained_type,
1448                            int               contained_type_start,
1449                            DBusTypeWriter   *sub)
1450 {
1451   int contained_type_len;
1452
1453   if (contained_type)
1454     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
1455   else
1456     contained_type_len = 0;
1457
1458   return _dbus_type_writer_recurse_contained_len (writer, container_type,
1459                                                   contained_type,
1460                                                   contained_type_start,
1461                                                   contained_type_len,
1462                                                   sub);
1463 }
1464
1465 dbus_bool_t
1466 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1467                              DBusTypeWriter *sub)
1468 {
1469   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1470
1471   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1472   _dbus_assert (!writer->type_pos_is_expectation ||
1473                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1474
1475 #if RECURSIVE_MARSHAL_TRACE
1476   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1477                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1478                  _dbus_type_to_string (writer->container_type));
1479   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1480                  sub, sub->type_pos, sub->value_pos,
1481                  sub->type_pos_is_expectation,
1482                  _dbus_type_to_string (sub->container_type));
1483 #endif
1484
1485   if (sub->container_type == DBUS_TYPE_STRUCT)
1486     {
1487       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1488         return FALSE;
1489     }
1490   else if (sub->container_type == DBUS_TYPE_ARRAY)
1491     {
1492       dbus_uint32_t len;
1493
1494       /* Set the array length */
1495       len = sub->value_pos - sub->u.array.start_pos;
1496       _dbus_marshal_set_uint32 (sub->value_str,
1497                                 sub->u.array.len_pos,
1498                                 len,
1499                                 sub->byte_order);
1500 #if RECURSIVE_MARSHAL_TRACE
1501       _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
1502                      len, sub->u.array.len_pos);
1503 #endif
1504     }
1505
1506   /* Now get type_pos right for the parent writer. Here are the cases:
1507    *
1508    * Cases !writer->type_pos_is_expectation:
1509    *   (in these cases we want to update to the new insertion point)
1510    *
1511    * - if we recursed into a STRUCT then we didn't know in advance
1512    *   what the types in the struct would be; so we have to fill in
1513    *   that information now.
1514    *       writer->type_pos = sub->type_pos
1515    *
1516    * - if we recursed into anything else, we knew the full array
1517    *   type, or knew the single typecode marking VARIANT, so
1518    *   writer->type_pos is already correct.
1519    *       writer->type_pos should remain as-is
1520    *
1521    * - note that the parent is never an ARRAY or VARIANT, if it were
1522    *   then type_pos_is_expectation would be TRUE. The parent
1523    *   is thus known to be a toplevel or STRUCT.
1524    *
1525    * Cases where writer->type_pos_is_expectation:
1526    *   (in these cases we want to update to next expected type to write)
1527    *
1528    * - we recursed from STRUCT into STRUCT and we didn't increment
1529    *   type_pos in the parent just to stay consistent with the
1530    *   !writer->type_pos_is_expectation case (though we could
1531    *   special-case this in recurse_struct instead if we wanted)
1532    *       writer->type_pos = sub->type_pos
1533    *
1534    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1535    *   for parent should have been incremented already
1536    *       writer->type_pos should remain as-is
1537    *
1538    * - we recursed from ARRAY into a sub-element, so type_pos in the
1539    *   parent is the element type and should remain the element type
1540    *   for the benefit of the next child element
1541    *       writer->type_pos should remain as-is
1542    *
1543    * - we recursed from VARIANT into its value, so type_pos in the
1544    *   parent makes no difference since there's only one value
1545    *   and we just finished writing it and won't use type_pos again
1546    *       writer->type_pos should remain as-is
1547    */
1548   if (sub->container_type == DBUS_TYPE_STRUCT &&
1549       (writer->container_type == DBUS_TYPE_STRUCT ||
1550        writer->container_type == DBUS_TYPE_INVALID))
1551     {
1552       /* Advance the parent to the next struct field */
1553       writer->type_pos = sub->type_pos;
1554     }
1555
1556   writer->value_pos = sub->value_pos;
1557
1558 #if RECURSIVE_MARSHAL_TRACE
1559   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1560                  writer, writer->type_pos, writer->value_pos,
1561                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1562 #endif
1563
1564   return TRUE;
1565 }
1566
1567 dbus_bool_t
1568 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1569                                int             type,
1570                                const void     *value)
1571 {
1572   dbus_bool_t retval;
1573
1574   /* First ensure that our type realloc will succeed */
1575   if (!_dbus_string_alloc_space (writer->type_str, 1))
1576     return FALSE;
1577
1578   retval = FALSE;
1579
1580   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1581     goto out;
1582
1583   if (!write_or_verify_typecode (writer, type))
1584     _dbus_assert_not_reached ("failed to write typecode after prealloc");
1585
1586   retval = TRUE;
1587
1588  out:
1589 #if RECURSIVE_MARSHAL_TRACE
1590   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1591                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1592 #endif
1593
1594   return retval;
1595 }
1596
1597 dbus_bool_t
1598 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1599                                int             type,
1600                                const void     *array,
1601                                int             array_len)
1602 {
1603
1604
1605 }
1606
1607 /**
1608  * Iterate through all values in the given reader,
1609  * writing a copy of each value to the writer.
1610  * The reader will be moved forward to its end position.
1611  *
1612  * @param writer the writer to copy to
1613  * @param reader the reader to copy from
1614  */
1615 dbus_bool_t
1616 _dbus_type_writer_write_reader (DBusTypeWriter *writer,
1617                                 DBusTypeReader *reader)
1618 {
1619   DBusTypeWriter orig;
1620   int orig_type_len;
1621   int orig_value_len;
1622   int new_bytes;
1623   int current_type;
1624
1625   orig = *writer;
1626   orig_type_len = _dbus_string_get_length (writer->type_str);
1627   orig_value_len = _dbus_string_get_length (writer->value_str);
1628
1629   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
1630     {
1631       if (_dbus_type_is_container (current_type))
1632         {
1633           DBusTypeReader subreader;
1634           DBusTypeWriter subwriter;
1635           const DBusString *sig_str;
1636           int sig_start;
1637           int sig_len;
1638
1639           _dbus_type_reader_recurse (reader, &subreader);
1640
1641           _dbus_type_reader_get_signature (&subreader, &sig_str,
1642                                            &sig_start, &sig_len);
1643
1644           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
1645                                                         sig_str, sig_start, sig_len,
1646                                                         &subwriter))
1647             goto oom;
1648
1649           if (!_dbus_type_writer_write_reader (&subwriter, &subreader))
1650             goto oom;
1651
1652           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
1653             goto oom;
1654         }
1655       else
1656         {
1657           DBusBasicValue val;
1658
1659           _dbus_assert (_dbus_type_is_basic (current_type));
1660
1661           _dbus_type_reader_read_basic (reader, &val);
1662
1663           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
1664             goto oom;
1665         }
1666
1667       _dbus_type_reader_next (reader);
1668     }
1669
1670   return TRUE;
1671
1672  oom:
1673   if (!writer->type_pos_is_expectation)
1674     {
1675       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
1676       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
1677     }
1678   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
1679   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
1680
1681   *writer = orig;
1682
1683   return FALSE;
1684 }
1685
1686 /** @} */ /* end of DBusMarshal group */
1687
1688 #ifdef DBUS_BUILD_TESTS
1689 #include "dbus-test.h"
1690 #include "dbus-list.h"
1691 #include <stdio.h>
1692 #include <stdlib.h>
1693
1694 /* Whether to do the OOM stuff */
1695 #define TEST_OOM_HANDLING 0
1696 /* We do start offset 0 through 9, to get various alignment cases. Still this
1697  * obviously makes the test suite run 10x as slow.
1698  */
1699 #define MAX_INITIAL_OFFSET 9
1700
1701 /* Largest iteration count to test copying, realignment,
1702  * etc. with. i.e. we only test this stuff with some of the smaller
1703  * data sets.
1704  */
1705 #define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000
1706
1707 typedef struct
1708 {
1709   int byte_order;
1710   int initial_offset;
1711   DBusString signature;
1712   DBusString body;
1713 } DataBlock;
1714
1715 typedef struct
1716 {
1717   int saved_sig_len;
1718   int saved_body_len;
1719 } DataBlockState;
1720
1721 #define N_FENCE_BYTES 5
1722 #define FENCE_BYTES_STR "abcde"
1723 #define INITIAL_PADDING_BYTE '\0'
1724
1725 static dbus_bool_t
1726 data_block_init (DataBlock *block,
1727                  int        byte_order,
1728                  int        initial_offset)
1729 {
1730   if (!_dbus_string_init (&block->signature))
1731     return FALSE;
1732
1733   if (!_dbus_string_init (&block->body))
1734     {
1735       _dbus_string_free (&block->signature);
1736       return FALSE;
1737     }
1738
1739   if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
1740                                   INITIAL_PADDING_BYTE) ||
1741       !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
1742                                   INITIAL_PADDING_BYTE) ||
1743       !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
1744       !_dbus_string_append (&block->body, FENCE_BYTES_STR))
1745     {
1746       _dbus_string_free (&block->signature);
1747       _dbus_string_free (&block->body);
1748       return FALSE;
1749     }
1750
1751   block->byte_order = byte_order;
1752   block->initial_offset = initial_offset;
1753
1754   return TRUE;
1755 }
1756
1757 static void
1758 data_block_save (DataBlock      *block,
1759                  DataBlockState *state)
1760 {
1761   state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
1762   state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
1763 }
1764
1765 static void
1766 data_block_restore (DataBlock      *block,
1767                     DataBlockState *state)
1768 {
1769   _dbus_string_delete (&block->signature,
1770                        state->saved_sig_len,
1771                        _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
1772   _dbus_string_delete (&block->body,
1773                        state->saved_body_len,
1774                        _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
1775 }
1776
1777 static void
1778 data_block_verify (DataBlock *block)
1779 {
1780   if (!_dbus_string_ends_with_c_str (&block->signature,
1781                                      FENCE_BYTES_STR))
1782     {
1783       int offset;
1784
1785       offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
1786       if (offset < 0)
1787         offset = 0;
1788
1789       _dbus_verbose_bytes_of_string (&block->signature,
1790                                      offset,
1791                                      _dbus_string_get_length (&block->signature) - offset);
1792       _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
1793     }
1794   if (!_dbus_string_ends_with_c_str (&block->body,
1795                                      FENCE_BYTES_STR))
1796     {
1797       int offset;
1798
1799       offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
1800       if (offset < 0)
1801         offset = 0;
1802
1803       _dbus_verbose_bytes_of_string (&block->body,
1804                                      offset,
1805                                      _dbus_string_get_length (&block->body) - offset);
1806       _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
1807     }
1808
1809   _dbus_assert (_dbus_string_validate_nul (&block->signature,
1810                                            0, block->initial_offset));
1811   _dbus_assert (_dbus_string_validate_nul (&block->body,
1812                                            0, block->initial_offset));
1813 }
1814
1815 static void
1816 data_block_free (DataBlock *block)
1817 {
1818   data_block_verify (block);
1819
1820   _dbus_string_free (&block->signature);
1821   _dbus_string_free (&block->body);
1822 }
1823
1824 static void
1825 data_block_reset (DataBlock *block)
1826 {
1827   data_block_verify (block);
1828
1829   _dbus_string_delete (&block->signature,
1830                        block->initial_offset,
1831                        _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
1832   _dbus_string_delete (&block->body,
1833                        block->initial_offset,
1834                        _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
1835
1836   data_block_verify (block);
1837 }
1838
1839 static void
1840 data_block_init_reader_writer (DataBlock      *block,
1841                                DBusTypeReader *reader,
1842                                DBusTypeWriter *writer)
1843 {
1844   if (reader)
1845     _dbus_type_reader_init (reader,
1846                             block->byte_order,
1847                             &block->signature,
1848                             block->initial_offset,
1849                             &block->body,
1850                             block->initial_offset);
1851
1852   if (writer)
1853     _dbus_type_writer_init (writer,
1854                             block->byte_order,
1855                             &block->signature,
1856                             _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
1857                             &block->body,
1858                             _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
1859 }
1860
1861 static void
1862 real_check_expected_type (DBusTypeReader *reader,
1863                           int             expected,
1864                           const char     *funcname,
1865                           int             line)
1866 {
1867   int t;
1868
1869   t = _dbus_type_reader_get_current_type (reader);
1870
1871   if (t != expected)
1872     {
1873       _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1874                   _dbus_type_to_string (t),
1875                   _dbus_type_to_string (expected),
1876                   funcname, line);
1877
1878       _dbus_assert_not_reached ("read wrong type");
1879     }
1880 }
1881
1882 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1883
1884 #define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \
1885  {                                                                                      \
1886     _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \
1887                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1888     _dbus_assert_not_reached ("test failed");                                           \
1889  }                                                                                      \
1890 } while (0)
1891
1892 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \
1893  {                                                                                      \
1894     _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \
1895                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1896     _dbus_assert_not_reached ("test failed");                                           \
1897  }                                                                                      \
1898  check_expected_type (reader, DBUS_TYPE_INVALID);                                       \
1899 } while (0)
1900
1901 typedef struct TestTypeNode               TestTypeNode;
1902 typedef struct TestTypeNodeClass          TestTypeNodeClass;
1903 typedef struct TestTypeNodeContainer      TestTypeNodeContainer;
1904 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1905
1906 struct TestTypeNode
1907 {
1908   const TestTypeNodeClass *klass;
1909 };
1910
1911 struct TestTypeNodeContainer
1912 {
1913   TestTypeNode base;
1914   DBusList    *children;
1915 };
1916
1917 struct TestTypeNodeClass
1918 {
1919   int typecode;
1920
1921   int instance_size;
1922
1923   int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
1924
1925   dbus_bool_t   (* construct)     (TestTypeNode   *node);
1926   void          (* destroy)       (TestTypeNode   *node);
1927
1928   dbus_bool_t (* write_value)     (TestTypeNode   *node,
1929                                    DataBlock      *block,
1930                                    DBusTypeWriter *writer,
1931                                    int             seed);
1932   dbus_bool_t (* read_value)      (TestTypeNode   *node,
1933                                    DataBlock      *block,
1934                                    DBusTypeReader *reader,
1935                                    int             seed);
1936   dbus_bool_t (* build_signature) (TestTypeNode   *node,
1937                                    DBusString     *str);
1938 };
1939
1940 struct TestTypeNodeContainerClass
1941 {
1942   TestTypeNodeClass base;
1943 };
1944
1945 static dbus_bool_t int32_write_value       (TestTypeNode   *node,
1946                                             DataBlock      *block,
1947                                             DBusTypeWriter *writer,
1948                                             int             seed);
1949 static dbus_bool_t int32_read_value        (TestTypeNode   *node,
1950                                             DataBlock      *block,
1951                                             DBusTypeReader *reader,
1952                                             int             seed);
1953 static dbus_bool_t int64_write_value       (TestTypeNode   *node,
1954                                             DataBlock      *block,
1955                                             DBusTypeWriter *writer,
1956                                             int             seed);
1957 static dbus_bool_t int64_read_value        (TestTypeNode   *node,
1958                                             DataBlock      *block,
1959                                             DBusTypeReader *reader,
1960                                             int             seed);
1961 static dbus_bool_t string_write_value      (TestTypeNode   *node,
1962                                             DataBlock      *block,
1963                                             DBusTypeWriter *writer,
1964                                             int             seed);
1965 static dbus_bool_t string_read_value       (TestTypeNode   *node,
1966                                             DataBlock      *block,
1967                                             DBusTypeReader *reader,
1968                                             int             seed);
1969 static dbus_bool_t bool_read_value         (TestTypeNode   *node,
1970                                             DataBlock      *block,
1971                                             DBusTypeReader *reader,
1972                                             int             seed);
1973 static dbus_bool_t bool_write_value        (TestTypeNode   *node,
1974                                             DataBlock      *block,
1975                                             DBusTypeWriter *writer,
1976                                             int             seed);
1977 static dbus_bool_t byte_read_value         (TestTypeNode   *node,
1978                                             DataBlock      *block,
1979                                             DBusTypeReader *reader,
1980                                             int             seed);
1981 static dbus_bool_t byte_write_value        (TestTypeNode   *node,
1982                                             DataBlock      *block,
1983                                             DBusTypeWriter *writer,
1984                                             int             seed);
1985 static dbus_bool_t double_read_value       (TestTypeNode   *node,
1986                                             DataBlock      *block,
1987                                             DBusTypeReader *reader,
1988                                             int             seed);
1989 static dbus_bool_t double_write_value      (TestTypeNode   *node,
1990                                             DataBlock      *block,
1991                                             DBusTypeWriter *writer,
1992                                             int             seed);
1993 static dbus_bool_t object_path_read_value  (TestTypeNode   *node,
1994                                             DataBlock      *block,
1995                                             DBusTypeReader *reader,
1996                                             int             seed);
1997 static dbus_bool_t object_path_write_value (TestTypeNode   *node,
1998                                             DataBlock      *block,
1999                                             DBusTypeWriter *writer,
2000                                             int             seed);
2001 static dbus_bool_t signature_read_value    (TestTypeNode   *node,
2002                                             DataBlock      *block,
2003                                             DBusTypeReader *reader,
2004                                             int             seed);
2005 static dbus_bool_t signature_write_value   (TestTypeNode   *node,
2006                                             DataBlock      *block,
2007                                             DBusTypeWriter *writer,
2008                                             int             seed);
2009 static dbus_bool_t struct_write_value      (TestTypeNode   *node,
2010                                             DataBlock      *block,
2011                                             DBusTypeWriter *writer,
2012                                             int             seed);
2013 static dbus_bool_t struct_read_value       (TestTypeNode   *node,
2014                                             DataBlock      *block,
2015                                             DBusTypeReader *reader,
2016                                             int             seed);
2017 static dbus_bool_t struct_build_signature  (TestTypeNode   *node,
2018                                             DBusString     *str);
2019 static dbus_bool_t array_write_value       (TestTypeNode   *node,
2020                                             DataBlock      *block,
2021                                             DBusTypeWriter *writer,
2022                                             int             seed);
2023 static dbus_bool_t array_read_value        (TestTypeNode   *node,
2024                                             DataBlock      *block,
2025                                             DBusTypeReader *reader,
2026                                             int             seed);
2027 static dbus_bool_t array_build_signature   (TestTypeNode   *node,
2028                                             DBusString     *str);
2029 static dbus_bool_t variant_write_value     (TestTypeNode   *node,
2030                                             DataBlock      *block,
2031                                             DBusTypeWriter *writer,
2032                                             int             seed);
2033 static dbus_bool_t variant_read_value      (TestTypeNode   *node,
2034                                             DataBlock      *block,
2035                                             DBusTypeReader *reader,
2036                                             int             seed);
2037 static void        container_destroy       (TestTypeNode   *node);
2038
2039
2040 static const TestTypeNodeClass int32_class = {
2041   DBUS_TYPE_INT32,
2042   sizeof (TestTypeNode),
2043   0,
2044   NULL,
2045   NULL,
2046   int32_write_value,
2047   int32_read_value,
2048   NULL
2049 };
2050
2051 static const TestTypeNodeClass uint32_class = {
2052   DBUS_TYPE_UINT32,
2053   sizeof (TestTypeNode),
2054   0,
2055   NULL,
2056   NULL,
2057   int32_write_value, /* recycle from int32 */
2058   int32_read_value,  /* recycle from int32 */
2059   NULL
2060 };
2061
2062 static const TestTypeNodeClass int64_class = {
2063   DBUS_TYPE_INT64,
2064   sizeof (TestTypeNode),
2065   0,
2066   NULL,
2067   NULL,
2068   int64_write_value,
2069   int64_read_value,
2070   NULL
2071 };
2072
2073 static const TestTypeNodeClass uint64_class = {
2074   DBUS_TYPE_UINT64,
2075   sizeof (TestTypeNode),
2076   0,
2077   NULL,
2078   NULL,
2079   int64_write_value, /* recycle from int64 */
2080   int64_read_value,  /* recycle from int64 */
2081   NULL
2082 };
2083
2084 static const TestTypeNodeClass string_0_class = {
2085   DBUS_TYPE_STRING,
2086   sizeof (TestTypeNode),
2087   0, /* string length */
2088   NULL,
2089   NULL,
2090   string_write_value,
2091   string_read_value,
2092   NULL
2093 };
2094
2095 static const TestTypeNodeClass string_1_class = {
2096   DBUS_TYPE_STRING,
2097   sizeof (TestTypeNode),
2098   1, /* string length */
2099   NULL,
2100   NULL,
2101   string_write_value,
2102   string_read_value,
2103   NULL
2104 };
2105
2106 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
2107 static const TestTypeNodeClass string_3_class = {
2108   DBUS_TYPE_STRING,
2109   sizeof (TestTypeNode),
2110   3, /* string length */
2111   NULL,
2112   NULL,
2113   string_write_value,
2114   string_read_value,
2115   NULL
2116 };
2117
2118 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
2119 static const TestTypeNodeClass string_8_class = {
2120   DBUS_TYPE_STRING,
2121   sizeof (TestTypeNode),
2122   8, /* string length */
2123   NULL,
2124   NULL,
2125   string_write_value,
2126   string_read_value,
2127   NULL
2128 };
2129
2130 static const TestTypeNodeClass bool_class = {
2131   DBUS_TYPE_BOOLEAN,
2132   sizeof (TestTypeNode),
2133   0,
2134   NULL,
2135   NULL,
2136   bool_write_value,
2137   bool_read_value,
2138   NULL
2139 };
2140
2141 static const TestTypeNodeClass byte_class = {
2142   DBUS_TYPE_BYTE,
2143   sizeof (TestTypeNode),
2144   0,
2145   NULL,
2146   NULL,
2147   byte_write_value,
2148   byte_read_value,
2149   NULL
2150 };
2151
2152 static const TestTypeNodeClass double_class = {
2153   DBUS_TYPE_DOUBLE,
2154   sizeof (TestTypeNode),
2155   0,
2156   NULL,
2157   NULL,
2158   double_write_value,
2159   double_read_value,
2160   NULL
2161 };
2162
2163 static const TestTypeNodeClass object_path_class = {
2164   DBUS_TYPE_OBJECT_PATH,
2165   sizeof (TestTypeNode),
2166   0,
2167   NULL,
2168   NULL,
2169   object_path_write_value,
2170   object_path_read_value,
2171   NULL
2172 };
2173
2174 static const TestTypeNodeClass signature_class = {
2175   DBUS_TYPE_SIGNATURE,
2176   sizeof (TestTypeNode),
2177   0,
2178   NULL,
2179   NULL,
2180   signature_write_value,
2181   signature_read_value,
2182   NULL
2183 };
2184
2185 static const TestTypeNodeClass struct_1_class = {
2186   DBUS_TYPE_STRUCT,
2187   sizeof (TestTypeNodeContainer),
2188   1, /* number of times children appear as fields */
2189   NULL,
2190   container_destroy,
2191   struct_write_value,
2192   struct_read_value,
2193   struct_build_signature
2194 };
2195
2196 static const TestTypeNodeClass struct_2_class = {
2197   DBUS_TYPE_STRUCT,
2198   sizeof (TestTypeNodeContainer),
2199   2, /* number of times children appear as fields */
2200   NULL,
2201   container_destroy,
2202   struct_write_value,
2203   struct_read_value,
2204   struct_build_signature
2205 };
2206
2207 static const TestTypeNodeClass array_0_class = {
2208   DBUS_TYPE_ARRAY,
2209   sizeof (TestTypeNodeContainer),
2210   0, /* number of array elements */
2211   NULL,
2212   container_destroy,
2213   array_write_value,
2214   array_read_value,
2215   array_build_signature
2216 };
2217
2218 static const TestTypeNodeClass array_1_class = {
2219   DBUS_TYPE_ARRAY,
2220   sizeof (TestTypeNodeContainer),
2221   1, /* number of array elements */
2222   NULL,
2223   container_destroy,
2224   array_write_value,
2225   array_read_value,
2226   array_build_signature
2227 };
2228
2229 static const TestTypeNodeClass array_2_class = {
2230   DBUS_TYPE_ARRAY,
2231   sizeof (TestTypeNodeContainer),
2232   2, /* number of array elements */
2233   NULL,
2234   container_destroy,
2235   array_write_value,
2236   array_read_value,
2237   array_build_signature
2238 };
2239
2240 static const TestTypeNodeClass array_9_class = {
2241   DBUS_TYPE_ARRAY,
2242   sizeof (TestTypeNodeContainer),
2243   9, /* number of array elements */
2244   NULL,
2245   container_destroy,
2246   array_write_value,
2247   array_read_value,
2248   array_build_signature
2249 };
2250
2251 static const TestTypeNodeClass variant_class = {
2252   DBUS_TYPE_VARIANT,
2253   sizeof (TestTypeNodeContainer),
2254   0,
2255   NULL,
2256   container_destroy,
2257   variant_write_value,
2258   variant_read_value,
2259   NULL
2260 };
2261
2262 static const TestTypeNodeClass* const
2263 basic_nodes[] = {
2264   &int32_class,
2265   &uint32_class,
2266   &int64_class,
2267   &uint64_class,
2268   &bool_class,
2269   &byte_class,
2270   &double_class,
2271   &string_0_class,
2272   &string_1_class,
2273   &string_3_class,
2274   &string_8_class,
2275   &object_path_class,
2276   &signature_class
2277 };
2278 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2279
2280 static const TestTypeNodeClass* const
2281 container_nodes[] = {
2282   &struct_1_class,
2283   &array_1_class,
2284   &struct_2_class,
2285   &array_0_class,
2286   &array_2_class,
2287   &variant_class
2288   /* array_9_class is omitted on purpose, it's too slow;
2289    * we only use it in one hardcoded test below
2290    */
2291 };
2292 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2293
2294 static TestTypeNode*
2295 node_new (const TestTypeNodeClass *klass)
2296 {
2297   TestTypeNode *node;
2298
2299   node = dbus_malloc0 (klass->instance_size);
2300   if (node == NULL)
2301     return NULL;
2302
2303   node->klass = klass;
2304
2305   if (klass->construct)
2306     {
2307       if (!(* klass->construct) (node))
2308         {
2309           dbus_free (node);
2310           return FALSE;
2311         }
2312     }
2313
2314   return node;
2315 }
2316
2317 static void
2318 node_destroy (TestTypeNode *node)
2319 {
2320   if (node->klass->destroy)
2321     (* node->klass->destroy) (node);
2322   dbus_free (node);
2323 }
2324
2325 static dbus_bool_t
2326 node_write_value (TestTypeNode   *node,
2327                   DataBlock      *block,
2328                   DBusTypeWriter *writer,
2329                   int             seed)
2330 {
2331   dbus_bool_t retval;
2332
2333   retval = (* node->klass->write_value) (node, block, writer, seed);
2334
2335 #if 0
2336   /* Handy to see where things break, but too expensive to do all the time */
2337   data_block_verify (block);
2338 #endif
2339
2340   return retval;
2341 }
2342
2343 static dbus_bool_t
2344 node_read_value (TestTypeNode   *node,
2345                  DataBlock      *block,
2346                  DBusTypeReader *reader,
2347                  int             seed)
2348 {
2349   DBusTypeMark mark;
2350   DBusTypeReader restored;
2351
2352   _dbus_type_reader_save_mark (reader, &mark);
2353
2354   if (!(* node->klass->read_value) (node, block, reader, seed))
2355     return FALSE;
2356
2357   _dbus_type_reader_init_from_mark (&restored,
2358                                     reader->byte_order,
2359                                     reader->type_str,
2360                                     reader->value_str,
2361                                     &mark);
2362
2363   if (!(* node->klass->read_value) (node, block, &restored, seed))
2364     return FALSE;
2365
2366   return TRUE;
2367 }
2368
2369 static dbus_bool_t
2370 node_build_signature (TestTypeNode *node,
2371                       DBusString   *str)
2372 {
2373   if (node->klass->build_signature)
2374     return (* node->klass->build_signature) (node, str);
2375   else
2376     return _dbus_string_append_byte (str, node->klass->typecode);
2377 }
2378
2379 static dbus_bool_t
2380 node_append_child (TestTypeNode *node,
2381                    TestTypeNode *child)
2382 {
2383   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2384
2385   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2386
2387   if (!_dbus_list_append (&container->children, child))
2388     _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 */
2389
2390   return TRUE;
2391 }
2392
2393 static int n_iterations_completed_total = 0;
2394 static int n_iterations_completed_this_test = 0;
2395 static int n_iterations_expected_this_test = 0;
2396
2397 typedef struct
2398 {
2399   const DBusString   *signature;
2400   DataBlock          *block;
2401   int                 type_offset;
2402   TestTypeNode      **nodes;
2403   int                 n_nodes;
2404 } NodeIterationData;
2405
2406
2407 static dbus_bool_t
2408 run_test_copy (NodeIterationData *nid)
2409 {
2410   DataBlock *src;
2411   DataBlock dest;
2412   dbus_bool_t retval;
2413   DBusTypeReader reader;
2414   DBusTypeWriter writer;
2415
2416   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
2417
2418   src = nid->block;
2419
2420   retval = FALSE;
2421
2422   if (!data_block_init (&dest, src->byte_order, src->initial_offset))
2423     return FALSE;
2424
2425   data_block_init_reader_writer (src, &reader, NULL);
2426   data_block_init_reader_writer (&dest, NULL, &writer);
2427
2428   /* DBusTypeWriter assumes it's writing into an existing signature,
2429    * so doesn't add nul on its own. We have to do that.
2430    */
2431   if (!_dbus_string_insert_byte (&dest.signature,
2432                                  dest.initial_offset, '\0'))
2433     goto out;
2434
2435   if (!_dbus_type_writer_write_reader (&writer, &reader))
2436     goto out;
2437
2438   /* Data blocks should now be identical */
2439   if (!_dbus_string_equal (&src->signature, &dest.signature))
2440     {
2441       _dbus_verbose ("SOURCE\n");
2442       _dbus_verbose_bytes_of_string (&src->signature, 0,
2443                                      _dbus_string_get_length (&src->signature));
2444       _dbus_verbose ("DEST\n");
2445       _dbus_verbose_bytes_of_string (&dest.signature, 0,
2446                                      _dbus_string_get_length (&dest.signature));
2447       _dbus_assert_not_reached ("signatures did not match");
2448     }
2449
2450   if (!_dbus_string_equal (&src->body, &dest.body))
2451     {
2452       _dbus_verbose ("SOURCE\n");
2453       _dbus_verbose_bytes_of_string (&src->body, 0,
2454                                      _dbus_string_get_length (&src->body));
2455       _dbus_verbose ("DEST\n");
2456       _dbus_verbose_bytes_of_string (&dest.body, 0,
2457                                      _dbus_string_get_length (&dest.body));
2458       _dbus_assert_not_reached ("bodies did not match");
2459     }
2460
2461   retval = TRUE;
2462
2463  out:
2464
2465   data_block_free (&dest);
2466
2467   return retval;
2468 }
2469
2470 static dbus_bool_t
2471 run_test_values_only_write (NodeIterationData *nid)
2472 {
2473   DBusTypeReader reader;
2474   DBusTypeWriter writer;
2475   int i;
2476   dbus_bool_t retval;
2477   int sig_len;
2478
2479   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
2480
2481   retval = FALSE;
2482
2483   data_block_reset (nid->block);
2484
2485   sig_len = _dbus_string_get_length (nid->signature);
2486
2487   _dbus_type_writer_init_values_only (&writer,
2488                                       nid->block->byte_order,
2489                                       nid->signature, 0,
2490                                       &nid->block->body,
2491                                       _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES);
2492   _dbus_type_reader_init (&reader,
2493                           nid->block->byte_order,
2494                           nid->signature, 0,
2495                           &nid->block->body,
2496                           nid->block->initial_offset);
2497
2498   i = 0;
2499   while (i < nid->n_nodes)
2500     {
2501       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2502         goto out;
2503
2504       ++i;
2505     }
2506
2507   /* if we wrote any typecodes then this would fail */
2508   _dbus_assert (sig_len == _dbus_string_get_length (nid->signature));
2509
2510   /* But be sure we wrote out the values correctly */
2511   i = 0;
2512   while (i < nid->n_nodes)
2513     {
2514       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
2515         goto out;
2516
2517       if (i + 1 == nid->n_nodes)
2518         NEXT_EXPECTING_FALSE (&reader);
2519       else
2520         NEXT_EXPECTING_TRUE (&reader);
2521
2522       ++i;
2523     }
2524
2525   retval = TRUE;
2526
2527  out:
2528   data_block_reset (nid->block);
2529   return retval;
2530 }
2531
2532 static dbus_bool_t
2533 run_test_nodes_iteration (void *data)
2534 {
2535   NodeIterationData *nid = data;
2536   DBusTypeReader reader;
2537   DBusTypeWriter writer;
2538   int i;
2539   dbus_bool_t retval;
2540
2541   /* Stuff to do:
2542    * 1. write the value
2543    * 2. strcmp-compare with the signature we built
2544    * 3. read the value
2545    * 4. type-iterate the signature and the value and see if they are the same type-wise
2546    */
2547   retval = FALSE;
2548
2549   data_block_init_reader_writer (nid->block,
2550                                  &reader, &writer);
2551
2552   /* DBusTypeWriter assumes it's writing into an existing signature,
2553    * so doesn't add nul on its own. We have to do that.
2554    */
2555   if (!_dbus_string_insert_byte (&nid->block->signature,
2556                                  nid->type_offset, '\0'))
2557     goto out;
2558
2559   i = 0;
2560   while (i < nid->n_nodes)
2561     {
2562       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2563         goto out;
2564
2565       ++i;
2566     }
2567
2568   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2569                                      &nid->block->signature, nid->type_offset))
2570     {
2571       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2572                   _dbus_string_get_const_data (nid->signature),
2573                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2574                   nid->type_offset);
2575       _dbus_assert_not_reached ("wrong signature");
2576     }
2577
2578   i = 0;
2579   while (i < nid->n_nodes)
2580     {
2581       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
2582         goto out;
2583
2584       if (i + 1 == nid->n_nodes)
2585         NEXT_EXPECTING_FALSE (&reader);
2586       else
2587         NEXT_EXPECTING_TRUE (&reader);
2588
2589       ++i;
2590     }
2591
2592   if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS)
2593     {
2594       if (!run_test_copy (nid))
2595         goto out;
2596
2597       if (!run_test_values_only_write (nid))
2598         goto out;
2599     }
2600
2601   /* FIXME type-iterate both signature and value and compare the resulting
2602    * tree to the node tree perhaps
2603    */
2604
2605   retval = TRUE;
2606
2607  out:
2608
2609   data_block_reset (nid->block);
2610
2611   return retval;
2612 }
2613
2614 static void
2615 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
2616                                      int               n_nodes,
2617                                      const DBusString *signature,
2618                                      int               byte_order,
2619                                      int               initial_offset)
2620 {
2621   DataBlock block;
2622   NodeIterationData nid;
2623
2624   if (!data_block_init (&block, byte_order, initial_offset))
2625     _dbus_assert_not_reached ("no memory");
2626
2627   nid.signature = signature;
2628   nid.block = &block;
2629   nid.type_offset = initial_offset;
2630   nid.nodes = nodes;
2631   nid.n_nodes = n_nodes;
2632
2633 #if TEST_OOM_HANDLING
2634   _dbus_test_oom_handling ("running test node",
2635                            run_test_nodes_iteration,
2636                            &nid);
2637 #else
2638   if (!run_test_nodes_iteration (&nid))
2639     _dbus_assert_not_reached ("no memory");
2640 #endif
2641
2642   data_block_free (&block);
2643 }
2644
2645 static void
2646 run_test_nodes (TestTypeNode **nodes,
2647                 int            n_nodes)
2648 {
2649   int i;
2650   DBusString signature;
2651
2652   if (!_dbus_string_init (&signature))
2653     _dbus_assert_not_reached ("no memory");
2654
2655   i = 0;
2656   while (i < n_nodes)
2657     {
2658       if (! node_build_signature (nodes[i], &signature))
2659         _dbus_assert_not_reached ("no memory");
2660
2661       ++i;
2662     }
2663
2664   _dbus_verbose (">>> test nodes with signature '%s'\n",
2665                  _dbus_string_get_const_data (&signature));
2666
2667   i = 0;
2668   while (i <= MAX_INITIAL_OFFSET)
2669     {
2670       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2671                                            DBUS_LITTLE_ENDIAN, i);
2672       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2673                                            DBUS_BIG_ENDIAN, i);
2674
2675       ++i;
2676     }
2677
2678   n_iterations_completed_this_test += 1;
2679   n_iterations_completed_total += 1;
2680
2681   if (n_iterations_completed_this_test == n_iterations_expected_this_test)
2682     {
2683       fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
2684                n_iterations_completed_this_test,
2685                n_iterations_completed_total);
2686     }
2687   /* this happens to turn out well with mod == 1 */
2688   else if ((n_iterations_completed_this_test %
2689             (int)(n_iterations_expected_this_test / 10.0)) == 1)
2690     {
2691       fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
2692     }
2693
2694   _dbus_string_free (&signature);
2695 }
2696
2697 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
2698
2699 static TestTypeNode*
2700 value_generator (int *ip)
2701 {
2702   int i = *ip;
2703   const TestTypeNodeClass *child_klass;
2704   const TestTypeNodeClass *container_klass;
2705   TestTypeNode *child;
2706   TestTypeNode *node;
2707
2708   _dbus_assert (i <= N_VALUES);
2709
2710   if (i == N_VALUES)
2711     {
2712       return NULL;
2713     }
2714   else if (i < N_BASICS)
2715     {
2716       node = node_new (basic_nodes[i]);
2717     }
2718   else
2719     {
2720       /* imagine an array:
2721        * container 0 of basic 0
2722        * container 0 of basic 1
2723        * container 0 of basic 2
2724        * container 1 of basic 0
2725        * container 1 of basic 1
2726        * container 1 of basic 2
2727        */
2728       i -= N_BASICS;
2729
2730       container_klass = container_nodes[i / N_BASICS];
2731       child_klass = basic_nodes[i % N_BASICS];
2732
2733       node = node_new (container_klass);
2734       child = node_new (child_klass);
2735
2736       node_append_child (node, child);
2737     }
2738
2739   *ip += 1; /* increment the generator */
2740
2741   return node;
2742 }
2743
2744 static void
2745 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2746                                       int                      n_nested)
2747 {
2748   TestTypeNode *root;
2749   TestTypeNode *container;
2750   TestTypeNode *child;
2751   int i;
2752
2753   root = node_new (container_klass);
2754   container = root;
2755   for (i = 1; i < n_nested; i++)
2756     {
2757       child = node_new (container_klass);
2758       node_append_child (container, child);
2759       container = child;
2760     }
2761
2762   /* container should now be the most-nested container */
2763
2764   i = 0;
2765   while ((child = value_generator (&i)))
2766     {
2767       node_append_child (container, child);
2768
2769       run_test_nodes (&root, 1);
2770
2771       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2772       node_destroy (child);
2773     }
2774
2775   node_destroy (root);
2776 }
2777
2778 static void
2779 start_next_test (const char *format,
2780                  int         expected)
2781 {
2782   n_iterations_completed_this_test = 0;
2783   n_iterations_expected_this_test = expected;
2784
2785   fprintf (stderr, ">>> >>> ");
2786   fprintf (stderr, format,
2787            n_iterations_expected_this_test);
2788 }
2789
2790 static void
2791 make_and_run_test_nodes (void)
2792 {
2793   int i, j, k, m;
2794
2795   /* We try to do this in order of "complicatedness" so that test
2796    * failures tend to show up in the simplest test case that
2797    * demonstrates the failure.  There are also some tests that run
2798    * more than once for this reason, first while going through simple
2799    * cases, second while going through a broader range of complex
2800    * cases.
2801    */
2802   /* Each basic node. The basic nodes should include:
2803    *
2804    * - each fixed-size type (in such a way that it has different values each time,
2805    *                         so we can tell if we mix two of them up)
2806    * - strings of various lengths
2807    * - object path
2808    * - signature
2809    */
2810   /* Each container node. The container nodes should include:
2811    *
2812    *  struct with 1 and 2 copies of the contained item
2813    *  array with 0, 1, 2 copies of the contained item
2814    *  variant
2815    */
2816   /*  Let a "value" be a basic node, or a container containing a single basic node.
2817    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2818    *  When iterating through all values to make combinations, do the basic types
2819    *  first and the containers second.
2820    */
2821   /* Each item is shown with its number of iterations to complete so
2822    * we can keep a handle on this unit test
2823    */
2824
2825   /* FIXME test just an empty body, no types at all */
2826
2827   start_next_test ("Each value by itself %d iterations\n", N_VALUES);
2828   {
2829     TestTypeNode *node;
2830     i = 0;
2831     while ((node = value_generator (&i)))
2832       {
2833         run_test_nodes (&node, 1);
2834
2835         node_destroy (node);
2836       }
2837   }
2838
2839   start_next_test ("All values in one big toplevel %d iteration\n", 1);
2840   {
2841     TestTypeNode *nodes[N_VALUES];
2842
2843     i = 0;
2844     while ((nodes[i] = value_generator (&i)))
2845       ;
2846
2847     run_test_nodes (nodes, N_VALUES);
2848
2849     for (i = 0; i < N_VALUES; i++)
2850       node_destroy (nodes[i]);
2851   }
2852
2853   start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
2854                    N_VALUES * N_VALUES);
2855   {
2856     TestTypeNode *nodes[2];
2857
2858     i = 0;
2859     while ((nodes[0] = value_generator (&i)))
2860       {
2861         j = 0;
2862         while ((nodes[1] = value_generator (&j)))
2863           {
2864             run_test_nodes (nodes, 2);
2865
2866             node_destroy (nodes[1]);
2867           }
2868
2869         node_destroy (nodes[0]);
2870       }
2871   }
2872
2873   start_next_test ("Each container containing each value %d iterations\n",
2874                    N_CONTAINERS * N_VALUES);
2875   for (i = 0; i < N_CONTAINERS; i++)
2876     {
2877       const TestTypeNodeClass *container_klass = container_nodes[i];
2878
2879       make_and_run_values_inside_container (container_klass, 1);
2880     }
2881
2882   n_iterations_completed_this_test = 0;
2883   n_iterations_expected_this_test = N_CONTAINERS * N_VALUES;
2884   _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2885                  n_iterations_completed_this_test);
2886   for (i = 0; i < N_CONTAINERS; i++)
2887     {
2888       const TestTypeNodeClass *container_klass = container_nodes[i];
2889
2890       make_and_run_values_inside_container (container_klass, 2);
2891     }
2892
2893   start_next_test ("Each container of same container of same container of each value %d iterations\n",
2894                    N_CONTAINERS * N_VALUES);
2895   for (i = 0; i < N_CONTAINERS; i++)
2896     {
2897       const TestTypeNodeClass *container_klass = container_nodes[i];
2898
2899       make_and_run_values_inside_container (container_klass, 3);
2900     }
2901
2902   start_next_test ("Each value,value pair inside a struct %d iterations\n",
2903                    N_VALUES * N_VALUES);
2904   {
2905     TestTypeNode *val1, *val2;
2906     TestTypeNode *node;
2907
2908     node = node_new (&struct_1_class);
2909
2910     i = 0;
2911     while ((val1 = value_generator (&i)))
2912       {
2913         j = 0;
2914         while ((val2 = value_generator (&j)))
2915           {
2916             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2917
2918             node_append_child (node, val1);
2919             node_append_child (node, val2);
2920
2921             run_test_nodes (&node, 1);
2922
2923             _dbus_list_clear (&container->children);
2924             node_destroy (val2);
2925           }
2926         node_destroy (val1);
2927       }
2928     node_destroy (node);
2929   }
2930
2931   start_next_test ("All values in one big struct %d iteration\n",
2932                    1);
2933   {
2934     TestTypeNode *node;
2935     TestTypeNode *child;
2936
2937     node = node_new (&struct_1_class);
2938
2939     i = 0;
2940     while ((child = value_generator (&i)))
2941       node_append_child (node, child);
2942
2943     run_test_nodes (&node, 1);
2944
2945     node_destroy (node);
2946   }
2947
2948   start_next_test ("Each value in a large array %d iterations\n",
2949                    N_VALUES);
2950   {
2951     TestTypeNode *val;
2952     TestTypeNode *node;
2953
2954     node = node_new (&array_9_class);
2955
2956     i = 0;
2957     while ((val = value_generator (&i)))
2958       {
2959         TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2960
2961         node_append_child (node, val);
2962
2963         run_test_nodes (&node, 1);
2964
2965         _dbus_list_clear (&container->children);
2966         node_destroy (val);
2967       }
2968
2969     node_destroy (node);
2970   }
2971
2972   start_next_test ("Each container of each container of each value %d iterations\n",
2973                    N_CONTAINERS * N_CONTAINERS * N_VALUES);
2974   for (i = 0; i < N_CONTAINERS; i++)
2975     {
2976       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2977       TestTypeNode *outer_container = node_new (outer_container_klass);
2978
2979       for (j = 0; j < N_CONTAINERS; j++)
2980         {
2981           TestTypeNode *child;
2982           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2983           TestTypeNode *inner_container = node_new (inner_container_klass);
2984
2985           node_append_child (outer_container, inner_container);
2986
2987           m = 0;
2988           while ((child = value_generator (&m)))
2989             {
2990               node_append_child (inner_container, child);
2991
2992               run_test_nodes (&outer_container, 1);
2993
2994               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2995               node_destroy (child);
2996             }
2997           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2998           node_destroy (inner_container);
2999         }
3000       node_destroy (outer_container);
3001     }
3002
3003   start_next_test ("Each container of each container of each container of each value %d iterations\n",
3004                    N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
3005   for (i = 0; i < N_CONTAINERS; i++)
3006     {
3007       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
3008       TestTypeNode *outer_container = node_new (outer_container_klass);
3009
3010       for (j = 0; j < N_CONTAINERS; j++)
3011         {
3012           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
3013           TestTypeNode *inner_container = node_new (inner_container_klass);
3014
3015           node_append_child (outer_container, inner_container);
3016
3017           for (k = 0; k < N_CONTAINERS; k++)
3018             {
3019               TestTypeNode *child;
3020               const TestTypeNodeClass *center_container_klass = container_nodes[k];
3021               TestTypeNode *center_container = node_new (center_container_klass);
3022
3023               node_append_child (inner_container, center_container);
3024
3025               m = 0;
3026               while ((child = value_generator (&m)))
3027                 {
3028                   node_append_child (center_container, child);
3029
3030                   run_test_nodes (&outer_container, 1);
3031
3032                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
3033                   node_destroy (child);
3034                 }
3035               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
3036               node_destroy (center_container);
3037             }
3038           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
3039           node_destroy (inner_container);
3040         }
3041       node_destroy (outer_container);
3042     }
3043
3044 #if 0
3045   /* This one takes a really long time, so comment it out for now */
3046   start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
3047                    N_VALUES * N_VALUES * N_VALUES);
3048   {
3049     TestTypeNode *nodes[3];
3050
3051     i = 0;
3052     while ((nodes[0] = value_generator (&i)))
3053       {
3054         j = 0;
3055         while ((nodes[1] = value_generator (&j)))
3056           {
3057             k = 0;
3058             while ((nodes[2] = value_generator (&k)))
3059               {
3060                 run_test_nodes (nodes, 3);
3061
3062                 node_destroy (nodes[2]);
3063               }
3064             node_destroy (nodes[1]);
3065           }
3066         node_destroy (nodes[0]);
3067       }
3068   }
3069 #endif /* #if 0 expensive test */
3070
3071   fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
3072            n_iterations_completed_total);
3073   fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
3074            MAX_INITIAL_OFFSET);
3075   fprintf (stderr, "out of memory handling %s tested\n",
3076            TEST_OOM_HANDLING ? "was" : "was not");
3077 }
3078
3079 dbus_bool_t _dbus_marshal_recursive_test (void);
3080
3081 dbus_bool_t
3082 _dbus_marshal_recursive_test (void)
3083 {
3084   make_and_run_test_nodes ();
3085
3086   return TRUE;
3087 }
3088
3089 #if 1
3090 dbus_bool_t _dbus_marshal_test (void);
3091 int
3092 main (int argc, char **argv)
3093 {
3094   _dbus_marshal_test ();
3095
3096   _dbus_marshal_recursive_test ();
3097
3098   return 0;
3099 }
3100 #endif /* main() */
3101
3102
3103 /*
3104  *
3105  *
3106  *         Implementations of each type node class
3107  *
3108  *
3109  *
3110  */
3111
3112
3113 #define SAMPLE_INT32           12345678
3114 #define SAMPLE_INT32_ALTERNATE 53781429
3115 static dbus_int32_t
3116 int32_from_seed (int seed)
3117 {
3118   /* Generate an integer value that's predictable from seed.  We could
3119    * just use seed itself, but that would only ever touch one byte of
3120    * the int so would miss some kinds of bug.
3121    */
3122   dbus_int32_t v;
3123
3124   v = 42; /* just to quiet compiler afaik */
3125   switch (seed % 5)
3126     {
3127     case 0:
3128       v = SAMPLE_INT32;
3129       break;
3130     case 1:
3131       v = SAMPLE_INT32_ALTERNATE;
3132       break;
3133     case 2:
3134       v = -1;
3135       break;
3136     case 3:
3137       v = _DBUS_INT_MAX;
3138       break;
3139     case 4:
3140       v = 1;
3141       break;
3142     }
3143
3144   if (seed > 1)
3145     v *= seed; /* wraps around eventually, which is fine */
3146
3147   return v;
3148 }
3149
3150 static dbus_bool_t
3151 int32_write_value (TestTypeNode   *node,
3152                    DataBlock      *block,
3153                    DBusTypeWriter *writer,
3154                    int             seed)
3155 {
3156   /* also used for uint32 */
3157   dbus_int32_t v;
3158
3159   v = int32_from_seed (seed);
3160
3161   return _dbus_type_writer_write_basic (writer,
3162                                         node->klass->typecode,
3163                                         &v);
3164 }
3165
3166 static dbus_bool_t
3167 int32_read_value (TestTypeNode   *node,
3168                   DataBlock      *block,
3169                   DBusTypeReader *reader,
3170                   int             seed)
3171 {
3172   /* also used for uint32 */
3173   dbus_int32_t v;
3174
3175   check_expected_type (reader, node->klass->typecode);
3176
3177   _dbus_type_reader_read_basic (reader,
3178                                 (dbus_int32_t*) &v);
3179
3180   _dbus_assert (v == int32_from_seed (seed));
3181
3182   return TRUE;
3183 }
3184
3185 #ifdef DBUS_HAVE_INT64
3186 static dbus_int64_t
3187 int64_from_seed (int seed)
3188 {
3189   dbus_int32_t v32;
3190   dbus_int64_t v;
3191
3192   v32 = int32_from_seed (seed);
3193
3194   v = - (dbus_int32_t) ~ v32;
3195   v |= (((dbus_int64_t)v32) << 32);
3196
3197   return v;
3198 }
3199 #endif
3200
3201 static dbus_bool_t
3202 int64_write_value (TestTypeNode   *node,
3203                    DataBlock      *block,
3204                    DBusTypeWriter *writer,
3205                    int             seed)
3206 {
3207 #ifdef DBUS_HAVE_INT64
3208   /* also used for uint64 */
3209   dbus_int64_t v;
3210
3211   v = int64_from_seed (seed);
3212
3213   return _dbus_type_writer_write_basic (writer,
3214                                         node->klass->typecode,
3215                                         &v);
3216 #else
3217   return TRUE;
3218 #endif
3219 }
3220
3221 static dbus_bool_t
3222 int64_read_value (TestTypeNode   *node,
3223                   DataBlock      *block,
3224                   DBusTypeReader *reader,
3225                   int             seed)
3226 {
3227 #ifdef DBUS_HAVE_INT64
3228   /* also used for uint64 */
3229   dbus_int64_t v;
3230
3231   check_expected_type (reader, node->klass->typecode);
3232
3233   _dbus_type_reader_read_basic (reader,
3234                                 (dbus_int64_t*) &v);
3235
3236   _dbus_assert (v == int64_from_seed (seed));
3237
3238   return TRUE;
3239 #else
3240   return TRUE;
3241 #endif
3242 }
3243
3244 #define MAX_SAMPLE_STRING_LEN 10
3245 static void
3246 string_from_seed (char *buf,
3247                   int   len,
3248                   int   seed)
3249 {
3250   int i;
3251   unsigned char v;
3252
3253   _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
3254
3255   v = (unsigned char) ('A' + seed);
3256
3257   i = 0;
3258   while (i < len)
3259     {
3260       if (v < 'A' || v > 'z')
3261         v = 'A';
3262
3263       buf[i] = v;
3264
3265       v += 1;
3266       ++i;
3267     }
3268
3269   buf[i] = '\0';
3270 }
3271
3272 static dbus_bool_t
3273 string_write_value (TestTypeNode   *node,
3274                     DataBlock      *block,
3275                     DBusTypeWriter *writer,
3276                     int             seed)
3277 {
3278   char buf[MAX_SAMPLE_STRING_LEN];
3279   const char *v_string = buf;
3280
3281   string_from_seed (buf, node->klass->subclass_detail,
3282                     seed);
3283
3284   return _dbus_type_writer_write_basic (writer,
3285                                         node->klass->typecode,
3286                                         &v_string);
3287 }
3288
3289 static dbus_bool_t
3290 string_read_value (TestTypeNode   *node,
3291                    DataBlock      *block,
3292                    DBusTypeReader *reader,
3293                    int             seed)
3294 {
3295   const char *v;
3296   char buf[MAX_SAMPLE_STRING_LEN];
3297
3298   check_expected_type (reader, node->klass->typecode);
3299
3300   _dbus_type_reader_read_basic (reader,
3301                                 (const char **) &v);
3302
3303   string_from_seed (buf, node->klass->subclass_detail,
3304                     seed);
3305
3306   if (strcmp (buf, v) != 0)
3307     {
3308       _dbus_warn ("read string '%s' expected '%s'\n",
3309                   v, buf);
3310       _dbus_assert_not_reached ("test failed");
3311     }
3312
3313   return TRUE;
3314 }
3315
3316 #define BOOL_FROM_SEED(seed) (seed % 2)
3317
3318 static dbus_bool_t
3319 bool_write_value (TestTypeNode   *node,
3320                   DataBlock      *block,
3321                   DBusTypeWriter *writer,
3322                   int             seed)
3323 {
3324   unsigned char v;
3325
3326   v = BOOL_FROM_SEED (seed);
3327
3328   return _dbus_type_writer_write_basic (writer,
3329                                         node->klass->typecode,
3330                                         &v);
3331 }
3332
3333 static dbus_bool_t
3334 bool_read_value (TestTypeNode   *node,
3335                  DataBlock      *block,
3336                  DBusTypeReader *reader,
3337                  int             seed)
3338 {
3339   unsigned char v;
3340
3341   check_expected_type (reader, node->klass->typecode);
3342
3343   _dbus_type_reader_read_basic (reader,
3344                                 (unsigned char*) &v);
3345
3346   _dbus_assert (v == BOOL_FROM_SEED (seed));
3347
3348   return TRUE;
3349 }
3350
3351 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
3352
3353 static dbus_bool_t
3354 byte_write_value (TestTypeNode   *node,
3355                   DataBlock      *block,
3356                   DBusTypeWriter *writer,
3357                   int             seed)
3358 {
3359   unsigned char v;
3360
3361   v = BYTE_FROM_SEED (seed);
3362
3363   return _dbus_type_writer_write_basic (writer,
3364                                         node->klass->typecode,
3365                                         &v);
3366 }
3367
3368 static dbus_bool_t
3369 byte_read_value (TestTypeNode   *node,
3370                  DataBlock      *block,
3371                  DBusTypeReader *reader,
3372                  int             seed)
3373 {
3374   unsigned char v;
3375
3376   check_expected_type (reader, node->klass->typecode);
3377
3378   _dbus_type_reader_read_basic (reader,
3379                                 (unsigned char*) &v);
3380
3381   _dbus_assert (v == BYTE_FROM_SEED (seed));
3382
3383   return TRUE;
3384 }
3385
3386 static double
3387 double_from_seed (int seed)
3388 {
3389   return SAMPLE_INT32 * (double) seed + 0.3;
3390 }
3391
3392 static dbus_bool_t
3393 double_write_value (TestTypeNode   *node,
3394                     DataBlock      *block,
3395                     DBusTypeWriter *writer,
3396                     int             seed)
3397 {
3398   double v;
3399
3400   v = double_from_seed (seed);
3401
3402   return _dbus_type_writer_write_basic (writer,
3403                                         node->klass->typecode,
3404                                         &v);
3405 }
3406
3407 static dbus_bool_t
3408 double_read_value (TestTypeNode   *node,
3409                    DataBlock      *block,
3410                    DBusTypeReader *reader,
3411                    int             seed)
3412 {
3413   double v;
3414   double expected;
3415
3416   check_expected_type (reader, node->klass->typecode);
3417
3418   _dbus_type_reader_read_basic (reader,
3419                                 (double*) &v);
3420
3421   expected = double_from_seed (seed);
3422
3423   if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
3424     {
3425 #ifdef DBUS_HAVE_INT64
3426       _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
3427                   expected, v,
3428                   *(dbus_uint64_t*)&expected,
3429                   *(dbus_uint64_t*)&v);
3430 #endif
3431       _dbus_assert_not_reached ("test failed");
3432     }
3433
3434   return TRUE;
3435 }
3436
3437
3438 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
3439 static void
3440 object_path_from_seed (char *buf,
3441                        int   seed)
3442 {
3443   int i;
3444   unsigned char v;
3445
3446   v = (unsigned char) ('A' + seed);
3447
3448   i = 0;
3449   while (i < 8)
3450     {
3451       if (v < 'A' || v > 'z')
3452         v = 'A';
3453
3454       buf[i] = '/';
3455       ++i;
3456       buf[i] = v;
3457       ++i;
3458
3459       v += 1;
3460     }
3461
3462   buf[i] = '\0';
3463 }
3464
3465 static dbus_bool_t
3466 object_path_write_value (TestTypeNode   *node,
3467                          DataBlock      *block,
3468                          DBusTypeWriter *writer,
3469                          int             seed)
3470 {
3471   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3472   const char *v_string = buf;
3473
3474   object_path_from_seed (buf, seed);
3475
3476   return _dbus_type_writer_write_basic (writer,
3477                                         node->klass->typecode,
3478                                         &v_string);
3479 }
3480
3481 static dbus_bool_t
3482 object_path_read_value (TestTypeNode   *node,
3483                         DataBlock      *block,
3484                         DBusTypeReader *reader,
3485                         int             seed)
3486 {
3487   const char *v;
3488   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3489
3490   check_expected_type (reader, node->klass->typecode);
3491
3492   _dbus_type_reader_read_basic (reader,
3493                                 (const char **) &v);
3494
3495   object_path_from_seed (buf, seed);
3496
3497   if (strcmp (buf, v) != 0)
3498     {
3499       _dbus_warn ("read object path '%s' expected '%s'\n",
3500                   v, buf);
3501       _dbus_assert_not_reached ("test failed");
3502     }
3503
3504   return TRUE;
3505 }
3506
3507
3508 #define MAX_SAMPLE_SIGNATURE_LEN 10
3509 static void
3510 signature_from_seed (char *buf,
3511                      int   seed)
3512 {
3513   int i;
3514   const char *s;
3515   const char *sample_signatures[] = {
3516     "",
3517     "ai",
3518     "x",
3519     "a(ii)",
3520     "asax"
3521   };
3522
3523   s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
3524
3525   for (i = 0; s[i]; i++)
3526     {
3527       buf[i] = s[i];
3528     }
3529   buf[i] = '\0';
3530 }
3531
3532 static dbus_bool_t
3533 signature_write_value (TestTypeNode   *node,
3534                        DataBlock      *block,
3535                        DBusTypeWriter *writer,
3536                        int             seed)
3537 {
3538   char buf[MAX_SAMPLE_SIGNATURE_LEN];
3539   const char *v_string = buf;
3540
3541   signature_from_seed (buf, seed);
3542
3543   return _dbus_type_writer_write_basic (writer,
3544                                         node->klass->typecode,
3545                                         &v_string);
3546 }
3547
3548 static dbus_bool_t
3549 signature_read_value (TestTypeNode   *node,
3550                       DataBlock      *block,
3551                       DBusTypeReader *reader,
3552                       int             seed)
3553 {
3554   const char *v;
3555   char buf[MAX_SAMPLE_SIGNATURE_LEN];
3556
3557   check_expected_type (reader, node->klass->typecode);
3558
3559   _dbus_type_reader_read_basic (reader,
3560                                 (const char **) &v);
3561
3562   signature_from_seed (buf, seed);
3563
3564   if (strcmp (buf, v) != 0)
3565     {
3566       _dbus_warn ("read signature value '%s' expected '%s'\n",
3567                   v, buf);
3568       _dbus_assert_not_reached ("test failed");
3569     }
3570
3571   return TRUE;
3572 }
3573
3574 static dbus_bool_t
3575 struct_write_value (TestTypeNode   *node,
3576                     DataBlock      *block,
3577                     DBusTypeWriter *writer,
3578                     int             seed)
3579 {
3580   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3581   DataBlockState saved;
3582   DBusTypeWriter sub;
3583   int i;
3584   int n_copies;
3585
3586   n_copies = node->klass->subclass_detail;
3587
3588   _dbus_assert (container->children != NULL);
3589
3590   data_block_save (block, &saved);
3591
3592   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT,
3593                                   NULL, 0,
3594                                   &sub))
3595     return FALSE;
3596
3597   i = 0;
3598   while (i < n_copies)
3599     {
3600       DBusList *link;
3601
3602       link = _dbus_list_get_first_link (&container->children);
3603       while (link != NULL)
3604         {
3605           TestTypeNode *child = link->data;
3606           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3607
3608           if (!node_write_value (child, block, &sub, i))
3609             {
3610               data_block_restore (block, &saved);
3611               return FALSE;
3612             }
3613
3614           link = next;
3615         }
3616
3617       ++i;
3618     }
3619
3620   if (!_dbus_type_writer_unrecurse (writer, &sub))
3621     {
3622       data_block_restore (block, &saved);
3623       return FALSE;
3624     }
3625
3626   return TRUE;
3627 }
3628
3629 static dbus_bool_t
3630 struct_read_value (TestTypeNode   *node,
3631                    DataBlock      *block,
3632                    DBusTypeReader *reader,
3633                    int             seed)
3634 {
3635   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3636   DBusTypeReader sub;
3637   int i;
3638   int n_copies;
3639
3640   n_copies = node->klass->subclass_detail;
3641
3642   check_expected_type (reader, DBUS_TYPE_STRUCT);
3643
3644   _dbus_type_reader_recurse (reader, &sub);
3645
3646   i = 0;
3647   while (i < n_copies)
3648     {
3649       DBusList *link;
3650
3651       link = _dbus_list_get_first_link (&container->children);
3652       while (link != NULL)
3653         {
3654           TestTypeNode *child = link->data;
3655           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3656
3657           if (!node_read_value (child, block, &sub, i))
3658             return FALSE;
3659
3660           if (i == (n_copies - 1) && next == NULL)
3661             NEXT_EXPECTING_FALSE (&sub);
3662           else
3663             NEXT_EXPECTING_TRUE (&sub);
3664
3665           link = next;
3666         }
3667
3668       ++i;
3669     }
3670
3671   return TRUE;
3672 }
3673
3674 static dbus_bool_t
3675 struct_build_signature (TestTypeNode   *node,
3676                         DBusString     *str)
3677 {
3678   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3679   int i;
3680   int orig_len;
3681   int n_copies;
3682
3683   n_copies = node->klass->subclass_detail;
3684
3685   orig_len = _dbus_string_get_length (str);
3686
3687   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3688     goto oom;
3689
3690   i = 0;
3691   while (i < n_copies)
3692     {
3693       DBusList *link;
3694
3695       link = _dbus_list_get_first_link (&container->children);
3696       while (link != NULL)
3697         {
3698           TestTypeNode *child = link->data;
3699           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3700
3701           if (!node_build_signature (child, str))
3702             goto oom;
3703
3704           link = next;
3705         }
3706
3707       ++i;
3708     }
3709
3710   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3711     goto oom;
3712
3713   return TRUE;
3714
3715  oom:
3716   _dbus_string_set_length (str, orig_len);
3717   return FALSE;
3718 }
3719
3720 static dbus_bool_t
3721 array_write_value (TestTypeNode   *node,
3722                    DataBlock      *block,
3723                    DBusTypeWriter *writer,
3724                    int             seed)
3725 {
3726   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3727   DataBlockState saved;
3728   DBusTypeWriter sub;
3729   DBusString element_signature;
3730   int i;
3731   int n_copies;
3732
3733   n_copies = node->klass->subclass_detail;
3734
3735   _dbus_assert (container->children != NULL);
3736
3737   data_block_save (block, &saved);
3738
3739   if (!_dbus_string_init (&element_signature))
3740     return FALSE;
3741
3742   if (!node_build_signature (_dbus_list_get_first (&container->children),
3743                              &element_signature))
3744     goto oom;
3745
3746   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
3747                                   &element_signature, 0,
3748                                   &sub))
3749     goto oom;
3750
3751   i = 0;
3752   while (i < n_copies)
3753     {
3754       DBusList *link;
3755
3756       link = _dbus_list_get_first_link (&container->children);
3757       while (link != NULL)
3758         {
3759           TestTypeNode *child = link->data;
3760           DBusList *next = _dbus_list_get_next_link (&container->children, link);
3761
3762           if (!node_write_value (child, block, &sub, i))
3763             goto oom;
3764
3765           link = next;
3766         }
3767
3768       ++i;
3769     }
3770
3771   if (!_dbus_type_writer_unrecurse (writer, &sub))
3772     goto oom;
3773
3774   _dbus_string_free (&element_signature);
3775   return TRUE;
3776
3777  oom:
3778   data_block_restore (block, &saved);
3779   _dbus_string_free (&element_signature);
3780   return FALSE;
3781 }
3782
3783 static dbus_bool_t
3784 array_read_value (TestTypeNode   *node,
3785                   DataBlock      *block,
3786                   DBusTypeReader *reader,
3787                   int             seed)
3788 {
3789   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3790   DBusTypeReader sub;
3791   int i;
3792   int n_copies;
3793
3794   n_copies = node->klass->subclass_detail;
3795
3796   check_expected_type (reader, DBUS_TYPE_ARRAY);
3797
3798   if (n_copies > 0)
3799     {
3800       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3801
3802       _dbus_type_reader_recurse (reader, &sub);
3803
3804       i = 0;
3805       while (i < n_copies)
3806         {
3807           DBusList *link;
3808
3809           link = _dbus_list_get_first_link (&container->children);
3810           while (link != NULL)
3811             {
3812               TestTypeNode *child = link->data;
3813               DBusList *next = _dbus_list_get_next_link (&container->children, link);
3814
3815               if (!node_read_value (child, block, &sub, i))
3816                 return FALSE;
3817
3818               if (i == (n_copies - 1) && next == NULL)
3819                 NEXT_EXPECTING_FALSE (&sub);
3820               else
3821                 NEXT_EXPECTING_TRUE (&sub);
3822
3823               link = next;
3824             }
3825
3826           ++i;
3827         }
3828     }
3829   else
3830     {
3831       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3832     }
3833
3834   return TRUE;
3835 }
3836
3837 static dbus_bool_t
3838 array_build_signature (TestTypeNode   *node,
3839                        DBusString     *str)
3840 {
3841   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3842   int orig_len;
3843
3844   orig_len = _dbus_string_get_length (str);
3845
3846   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3847     goto oom;
3848
3849   if (!node_build_signature (_dbus_list_get_first (&container->children),
3850                              str))
3851     goto oom;
3852
3853   return TRUE;
3854
3855  oom:
3856   _dbus_string_set_length (str, orig_len);
3857   return FALSE;
3858 }
3859
3860  /* 10 is random just to add another seed that we use in the suite */
3861 #define VARIANT_SEED 10
3862
3863 static dbus_bool_t
3864 variant_write_value (TestTypeNode   *node,
3865                      DataBlock      *block,
3866                      DBusTypeWriter *writer,
3867                      int             seed)
3868 {
3869   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3870   DataBlockState saved;
3871   DBusTypeWriter sub;
3872   DBusString content_signature;
3873   TestTypeNode *child;
3874
3875   _dbus_assert (container->children != NULL);
3876   _dbus_assert (_dbus_list_length_is_one (&container->children));
3877
3878   child = _dbus_list_get_first (&container->children);
3879
3880   data_block_save (block, &saved);
3881
3882   if (!_dbus_string_init (&content_signature))
3883     return FALSE;
3884
3885   if (!node_build_signature (child,
3886                              &content_signature))
3887     goto oom;
3888
3889   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT,
3890                                   &content_signature, 0,
3891                                   &sub))
3892     goto oom;
3893
3894   if (!node_write_value (child, block, &sub, VARIANT_SEED))
3895     goto oom;
3896
3897   if (!_dbus_type_writer_unrecurse (writer, &sub))
3898     goto oom;
3899
3900   _dbus_string_free (&content_signature);
3901   return TRUE;
3902
3903  oom:
3904   data_block_restore (block, &saved);
3905   _dbus_string_free (&content_signature);
3906   return FALSE;
3907 }
3908
3909 static dbus_bool_t
3910 variant_read_value (TestTypeNode   *node,
3911                     DataBlock      *block,
3912                     DBusTypeReader *reader,
3913                     int             seed)
3914 {
3915   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3916   DBusTypeReader sub;
3917   TestTypeNode *child;
3918
3919   _dbus_assert (container->children != NULL);
3920   _dbus_assert (_dbus_list_length_is_one (&container->children));
3921
3922   child = _dbus_list_get_first (&container->children);
3923
3924   check_expected_type (reader, DBUS_TYPE_VARIANT);
3925
3926   _dbus_type_reader_recurse (reader, &sub);
3927
3928   if (!node_read_value (child, block, &sub, VARIANT_SEED))
3929     return FALSE;
3930
3931   NEXT_EXPECTING_FALSE (&sub);
3932
3933   return TRUE;
3934 }
3935
3936 static void
3937 container_destroy (TestTypeNode *node)
3938 {
3939   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3940   DBusList *link;
3941
3942   link = _dbus_list_get_first_link (&container->children);
3943   while (link != NULL)
3944     {
3945       TestTypeNode *child = link->data;
3946       DBusList *next = _dbus_list_get_next_link (&container->children, link);
3947
3948       node_destroy (child);
3949
3950       _dbus_list_free_link (link);
3951
3952       link = next;
3953     }
3954 }
3955
3956 #endif /* DBUS_BUILD_TESTS */