2005-01-15 Havoc Pennington <hp@redhat.com>
[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_READ_TRACE  0
33 #define RECURSIVE_MARSHAL_WRITE_TRACE 0
34
35 static void
36 free_fixups (DBusList **fixups)
37 {
38   DBusList *link;
39
40   link = _dbus_list_get_first_link (fixups);
41   while (link != NULL)
42     {
43       DBusList *next;
44
45       next = _dbus_list_get_next_link (fixups, link);
46
47       dbus_free (link->data);
48       _dbus_list_free_link (link);
49
50       link = next;
51     }
52
53   *fixups = NULL;
54 }
55
56 static void
57 apply_and_free_fixups (DBusList      **fixups,
58                        DBusTypeReader *reader)
59 {
60   DBusList *link;
61
62 #if RECURSIVE_MARSHAL_WRITE_TRACE
63   if (*fixups)
64     _dbus_verbose (" %d FIXUPS to apply\n",
65                    _dbus_list_get_length (fixups));
66 #endif
67
68   link = _dbus_list_get_first_link (fixups);
69   while (link != NULL)
70     {
71       DBusList *next;
72
73       next = _dbus_list_get_next_link (fixups, link);
74
75       if (reader)
76         {
77           DBusArrayLenFixup *f;
78
79           f = link->data;
80
81 #if RECURSIVE_MARSHAL_WRITE_TRACE
82           _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",
83                          reader, f->len_pos_in_reader, f->new_len,
84                          _dbus_marshal_read_uint32 (reader->value_str,
85                                                     f->len_pos_in_reader,
86                                                     reader->byte_order, NULL));
87 #endif
88
89           _dbus_marshal_set_uint32 ((DBusString*) reader->value_str,
90                                     f->len_pos_in_reader,
91                                     f->new_len,
92                                     reader->byte_order);
93         }
94
95       dbus_free (link->data);
96       _dbus_list_free_link (link);
97
98       link = next;
99     }
100
101   *fixups = NULL;
102 }
103
104 struct DBusTypeReaderClass
105 {
106   const char *name;
107   int         id;         /* index in all_reader_classes */
108   dbus_bool_t types_only; /* only iterates over types, not values */
109   void        (* recurse)          (DBusTypeReader        *sub,
110                                     DBusTypeReader        *parent);
111   dbus_bool_t (* check_finished)   (const DBusTypeReader  *reader);
112   void        (* next)             (DBusTypeReader        *reader,
113                                     int                    current_type);
114   void        (* init_from_mark)   (DBusTypeReader        *reader,
115                                     const DBusTypeMark    *mark);
116 };
117
118 static int
119 first_type_in_signature (const DBusString *str,
120                          int               pos)
121 {
122   int t;
123
124   t = _dbus_string_get_byte (str, pos);
125
126   if (t == DBUS_STRUCT_BEGIN_CHAR)
127     return DBUS_TYPE_STRUCT;
128   else
129     return t;
130 }
131
132 static int
133 element_type_get_alignment (const DBusString *str,
134                             int               pos)
135 {
136   return _dbus_type_get_alignment (first_type_in_signature (str, pos));
137 }
138
139 static void
140 reader_init (DBusTypeReader    *reader,
141              int                byte_order,
142              const DBusString  *type_str,
143              int                type_pos,
144              const DBusString  *value_str,
145              int                value_pos)
146 {
147   reader->byte_order = byte_order;
148   reader->finished = FALSE;
149   reader->type_str = type_str;
150   reader->type_pos = type_pos;
151   reader->value_str = value_str;
152   reader->value_pos = value_pos;
153 }
154
155 static void
156 base_reader_recurse (DBusTypeReader *sub,
157                      DBusTypeReader *parent)
158 {
159   /* point subreader at the same place as parent */
160   reader_init (sub,
161                parent->byte_order,
162                parent->type_str,
163                parent->type_pos,
164                parent->value_str,
165                parent->value_pos);
166 }
167
168 static void
169 struct_types_only_reader_recurse (DBusTypeReader *sub,
170                                   DBusTypeReader *parent)
171 {
172   base_reader_recurse (sub, parent);
173
174   _dbus_assert (_dbus_string_get_byte (sub->type_str,
175                                        sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
176
177   sub->type_pos += 1;
178 }
179
180 static void
181 struct_reader_recurse (DBusTypeReader *sub,
182                        DBusTypeReader *parent)
183 {
184   struct_types_only_reader_recurse (sub, parent);
185
186   /* struct has 8 byte alignment */
187   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
188 }
189
190 static void
191 array_types_only_reader_recurse (DBusTypeReader *sub,
192                                  DBusTypeReader *parent)
193 {
194   base_reader_recurse (sub, parent);
195
196   /* point type_pos at the array element type */
197   sub->type_pos += 1;
198
199   /* Init with values likely to crash things if misused */
200   sub->u.array.start_pos = _DBUS_INT_MAX;
201   sub->array_len_offset = 7;
202 }
203
204 /* array_len_offset is the offset back from start_pos to end of the len */
205 #define ARRAY_READER_LEN_POS(reader) \
206   ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4)
207
208 static int
209 array_reader_get_array_len (const DBusTypeReader *reader)
210 {
211   dbus_uint32_t array_len;
212   int len_pos;
213
214   len_pos = ARRAY_READER_LEN_POS (reader);
215
216   _dbus_marshal_read_basic (reader->value_str,
217                             len_pos,
218                             DBUS_TYPE_UINT32,
219                             &array_len,
220                             reader->byte_order,
221                             NULL);
222
223 #if RECURSIVE_MARSHAL_READ_TRACE
224   _dbus_verbose ("   reader %p len_pos %d array len %u len_offset %d\n",
225                  reader, len_pos, array_len, reader->array_len_offset);
226 #endif
227
228   _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
229
230   return array_len;
231 }
232
233 static void
234 array_reader_recurse (DBusTypeReader *sub,
235                       DBusTypeReader *parent)
236 {
237   int alignment;
238   int len_pos;
239
240   array_types_only_reader_recurse (sub, parent);
241
242   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
243
244   len_pos = sub->value_pos;
245
246   sub->value_pos += 4; /* for the length */
247
248   alignment = element_type_get_alignment (sub->type_str,
249                                           sub->type_pos);
250
251   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
252
253   sub->u.array.start_pos = sub->value_pos;
254   _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
255   sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
256
257 #if RECURSIVE_MARSHAL_READ_TRACE
258   _dbus_verbose ("    type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
259                  sub,
260                  sub->u.array.start_pos,
261                  sub->array_len_offset,
262                  array_reader_get_array_len (sub),
263                  _dbus_type_to_string (first_type_in_signature (sub->type_str,
264                                                                 sub->type_pos)));
265 #endif
266 }
267
268 static void
269 variant_reader_recurse (DBusTypeReader *sub,
270                         DBusTypeReader *parent)
271 {
272   int sig_len;
273
274   base_reader_recurse (sub, parent);
275
276   /* Variant is 1 byte sig length (without nul), signature with nul,
277    * padding to 8-boundary, then values
278    */
279
280   sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
281
282   sub->type_str = sub->value_str;
283   sub->type_pos = sub->value_pos + 1;
284
285   sub->value_pos = sub->type_pos + sig_len + 1;
286
287   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
288
289 #if RECURSIVE_MARSHAL_READ_TRACE
290   _dbus_verbose ("    type reader %p variant containing '%s'\n",
291                  sub,
292                  _dbus_string_get_const_data_len (sub->type_str,
293                                                   sub->type_pos, 0));
294 #endif
295 }
296
297 static dbus_bool_t
298 array_reader_check_finished (const DBusTypeReader *reader)
299 {
300   int end_pos;
301
302   /* return the array element type if elements remain, and
303    * TYPE_INVALID otherwise
304    */
305
306   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
307
308   _dbus_assert (reader->value_pos <= end_pos);
309   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
310
311   return reader->value_pos == end_pos;
312 }
313
314 static void
315 skip_one_complete_type (const DBusString *type_str,
316                         int              *type_pos)
317 {
318   while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
319     *type_pos += 1;
320
321   if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
322     {
323       int depth;
324       depth = 1;
325       *type_pos += 1;
326       while (depth > 0)
327         {
328           switch (_dbus_string_get_byte (type_str, *type_pos))
329             {
330             case DBUS_STRUCT_BEGIN_CHAR:
331               depth += 1;
332               break;
333             case DBUS_STRUCT_END_CHAR:
334               depth -= 1;
335               break;
336             case DBUS_TYPE_INVALID:
337               _dbus_assert_not_reached ("unbalanced parens in signature");
338               break;
339             }
340           *type_pos += 1;
341         }
342     }
343   else
344     *type_pos += 1;
345 }
346
347 static int
348 find_len_of_complete_type (const DBusString *type_str,
349                            int               type_pos)
350 {
351   int end;
352
353   end = type_pos;
354
355   skip_one_complete_type (type_str, &end);
356
357   return end - type_pos;
358 }
359
360 static void
361 base_reader_next (DBusTypeReader *reader,
362                   int             current_type)
363 {
364   switch (current_type)
365     {
366     case DBUS_TYPE_STRUCT:
367     case DBUS_TYPE_VARIANT:
368       /* Scan forward over the entire container contents */
369       {
370         DBusTypeReader sub;
371
372         if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT)
373           ;
374         else
375           {
376             /* Recurse into the struct or variant */
377             _dbus_type_reader_recurse (reader, &sub);
378
379             /* Skip everything in this subreader */
380             while (_dbus_type_reader_next (&sub))
381               {
382                 /* nothing */;
383               }
384           }
385         if (!reader->klass->types_only)
386           reader->value_pos = sub.value_pos;
387
388         /* Now we are at the end of this container; for variants, the
389          * subreader's type_pos is totally inapplicable (it's in the
390          * value string) but we know that we increment by one past the
391          * DBUS_TYPE_VARIANT
392          */
393         if (current_type == DBUS_TYPE_VARIANT)
394           reader->type_pos += 1;
395         else
396           reader->type_pos = sub.type_pos;
397       }
398       break;
399
400     case DBUS_TYPE_ARRAY:
401       {
402         if (!reader->klass->types_only)
403           _dbus_marshal_skip_array (reader->value_str,
404                                     first_type_in_signature (reader->type_str,
405                                                              reader->type_pos + 1),
406                                     reader->byte_order,
407                                     &reader->value_pos);
408
409         skip_one_complete_type (reader->type_str, &reader->type_pos);
410       }
411       break;
412
413     default:
414       if (!reader->klass->types_only)
415         _dbus_marshal_skip_basic (reader->value_str,
416                                   current_type, reader->byte_order,
417                                   &reader->value_pos);
418
419       reader->type_pos += 1;
420       break;
421     }
422 }
423
424 static void
425 struct_reader_next (DBusTypeReader *reader,
426                     int             current_type)
427 {
428   int t;
429
430   base_reader_next (reader, current_type);
431
432   /* for STRUCT containers we return FALSE at the end of the struct,
433    * for INVALID we return FALSE at the end of the signature.
434    * In both cases we arrange for get_current_type() to return INVALID
435    * which is defined to happen iff we're at the end (no more next())
436    */
437   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
438   if (t == DBUS_STRUCT_END_CHAR)
439     {
440       reader->type_pos += 1;
441       reader->finished = TRUE;
442     }
443 }
444
445 static void
446 array_types_only_reader_next (DBusTypeReader *reader,
447                               int             current_type)
448 {
449   /* We have one "element" to be iterated over
450    * in each array, which is its element type.
451    * So the finished flag indicates whether we've
452    * iterated over it yet or not.
453    */
454   reader->finished = TRUE;
455 }
456
457 static void
458 array_reader_next (DBusTypeReader *reader,
459                    int             current_type)
460 {
461   /* Skip one array element */
462   int end_pos;
463
464   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
465
466 #if RECURSIVE_MARSHAL_READ_TRACE
467   _dbus_verbose ("  reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
468                  reader,
469                  reader->u.array.start_pos,
470                  end_pos, reader->value_pos,
471                  _dbus_type_to_string (current_type));
472 #endif
473
474   _dbus_assert (reader->value_pos < end_pos);
475   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
476
477   switch (first_type_in_signature (reader->type_str,
478                                    reader->type_pos))
479     {
480     case DBUS_TYPE_STRUCT:
481     case DBUS_TYPE_VARIANT:
482       {
483         DBusTypeReader sub;
484
485         /* Recurse into the struct or variant */
486         _dbus_type_reader_recurse (reader, &sub);
487
488         /* Skip everything in this element */
489         while (_dbus_type_reader_next (&sub))
490           {
491             /* nothing */;
492           }
493
494         /* Now we are at the end of this element */
495         reader->value_pos = sub.value_pos;
496       }
497       break;
498
499     case DBUS_TYPE_ARRAY:
500       {
501         _dbus_marshal_skip_array (reader->value_str,
502                                   first_type_in_signature (reader->type_str,
503                                                            reader->type_pos + 1),
504                                   reader->byte_order,
505                                   &reader->value_pos);
506       }
507       break;
508
509     default:
510       {
511         _dbus_marshal_skip_basic (reader->value_str,
512                                   current_type, reader->byte_order,
513                                   &reader->value_pos);
514       }
515       break;
516     }
517
518 #if RECURSIVE_MARSHAL_READ_TRACE
519   _dbus_verbose ("  reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
520                  reader,
521                  reader->u.array.start_pos,
522                  end_pos, reader->value_pos,
523                  _dbus_type_to_string (current_type));
524 #endif
525
526   _dbus_assert (reader->value_pos <= end_pos);
527
528   if (reader->value_pos == end_pos)
529     {
530       skip_one_complete_type (reader->type_str,
531                               &reader->type_pos);
532     }
533 }
534
535 static void
536 array_init_from_mark (DBusTypeReader     *reader,
537                       const DBusTypeMark *mark)
538 {
539   /* Fill in the array-specific fields from the mark. The general
540    * fields are already filled in.
541    */
542   reader->u.array.start_pos = mark->array_start_pos;
543   reader->array_len_offset = mark->array_len_offset;
544 }
545
546 static const DBusTypeReaderClass body_reader_class = {
547   "body", 0,
548   FALSE,
549   NULL, /* body is always toplevel, so doesn't get recursed into */
550   NULL,
551   base_reader_next,
552   NULL
553 };
554
555 static const DBusTypeReaderClass body_types_only_reader_class = {
556   "body types", 1,
557   TRUE,
558   NULL, /* body is always toplevel, so doesn't get recursed into */
559   NULL,
560   base_reader_next,
561   NULL
562 };
563
564 static const DBusTypeReaderClass struct_reader_class = {
565   "struct", 2,
566   FALSE,
567   struct_reader_recurse,
568   NULL,
569   struct_reader_next,
570   NULL
571 };
572
573 static const DBusTypeReaderClass struct_types_only_reader_class = {
574   "struct types", 3,
575   TRUE,
576   struct_types_only_reader_recurse,
577   NULL,
578   struct_reader_next,
579   NULL
580 };
581
582 static const DBusTypeReaderClass array_reader_class = {
583   "array", 4,
584   FALSE,
585   array_reader_recurse,
586   array_reader_check_finished,
587   array_reader_next,
588   array_init_from_mark
589 };
590
591 static const DBusTypeReaderClass array_types_only_reader_class = {
592   "array types", 5,
593   TRUE,
594   array_types_only_reader_recurse,
595   NULL,
596   array_types_only_reader_next,
597   NULL
598 };
599
600 static const DBusTypeReaderClass variant_reader_class = {
601   "variant", 6,
602   FALSE,
603   variant_reader_recurse,
604   NULL,
605   base_reader_next,
606   NULL
607 };
608
609 static const DBusTypeReaderClass const *
610 all_reader_classes[] = {
611   &body_reader_class,
612   &body_types_only_reader_class,
613   &struct_reader_class,
614   &struct_types_only_reader_class,
615   &array_reader_class,
616   &array_types_only_reader_class,
617   &variant_reader_class
618 };
619
620 void
621 _dbus_type_reader_init (DBusTypeReader    *reader,
622                         int                byte_order,
623                         const DBusString  *type_str,
624                         int                type_pos,
625                         const DBusString  *value_str,
626                         int                value_pos)
627 {
628   reader->klass = &body_reader_class;
629
630   reader_init (reader, byte_order, type_str, type_pos,
631                value_str, value_pos);
632
633 #if RECURSIVE_MARSHAL_READ_TRACE
634   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
635                  reader, reader->type_pos, reader->value_pos,
636                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
637 #endif
638 }
639
640 void
641 _dbus_type_reader_init_from_mark (DBusTypeReader     *reader,
642                                   int                 byte_order,
643                                   const DBusString   *type_str,
644                                   const DBusString   *value_str,
645                                   const DBusTypeMark *mark)
646 {
647   reader->klass = all_reader_classes[mark->container_type];
648
649   reader_init (reader, byte_order,
650                mark->type_pos_in_value_str ? value_str : type_str,
651                mark->type_pos,
652                value_str, mark->value_pos);
653
654   if (reader->klass->init_from_mark)
655     (* reader->klass->init_from_mark) (reader, mark);
656
657 #if RECURSIVE_MARSHAL_READ_TRACE
658   _dbus_verbose ("  type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",
659                  reader, reader->type_pos, reader->value_pos,
660                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
661 #endif
662 }
663
664 void
665 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
666                                    const DBusString  *type_str,
667                                    int                type_pos)
668 {
669   reader->klass = &body_types_only_reader_class;
670
671   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
672                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
673
674 #if RECURSIVE_MARSHAL_READ_TRACE
675   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
676                  reader, reader->type_pos,
677                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
678 #endif
679 }
680
681 void
682 _dbus_type_reader_init_types_only_from_mark (DBusTypeReader     *reader,
683                                              const DBusString   *type_str,
684                                              const DBusTypeMark *mark)
685 {
686   reader->klass = all_reader_classes[mark->container_type];
687   _dbus_assert (reader->klass->types_only);
688   _dbus_assert (!mark->type_pos_in_value_str);
689
690   reader_init (reader, DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
691                type_str, mark->type_pos,
692                NULL, _DBUS_INT_MAX /* crashes if we screw up */);
693
694   if (reader->klass->init_from_mark)
695     (* reader->klass->init_from_mark) (reader, mark);
696
697 #if RECURSIVE_MARSHAL_READ_TRACE
698   _dbus_verbose ("  type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",
699                  reader, reader->type_pos,
700                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
701 #endif
702 }
703
704 void
705 _dbus_type_reader_save_mark (const DBusTypeReader *reader,
706                              DBusTypeMark         *mark)
707 {
708   mark->type_pos_in_value_str = (reader->type_str == reader->value_str);
709   mark->container_type = reader->klass->id;
710   _dbus_assert (all_reader_classes[reader->klass->id] == reader->klass);
711
712   mark->type_pos = reader->type_pos;
713   mark->value_pos = reader->value_pos;
714
715   /* these are just junk if the reader isn't really an array of course */
716   mark->array_len_offset = reader->array_len_offset;
717   mark->array_start_pos = reader->u.array.start_pos;
718 }
719
720 int
721 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
722 {
723   int t;
724
725   if (reader->finished ||
726       (reader->klass->check_finished &&
727        (* reader->klass->check_finished) (reader)))
728     t = DBUS_TYPE_INVALID;
729   else
730     t = first_type_in_signature (reader->type_str,
731                                  reader->type_pos);
732
733   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
734   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
735
736 #if 0
737   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
738                  reader, reader->type_pos,
739                  _dbus_type_to_string (t));
740 #endif
741
742   return t;
743 }
744
745 int
746 _dbus_type_reader_get_array_type (const DBusTypeReader  *reader)
747 {
748   int element_type;
749
750   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
751
752   element_type = first_type_in_signature (reader->type_str,
753                                           reader->type_pos + 1);
754
755   return element_type;
756 }
757
758 int
759 _dbus_type_reader_get_value_pos (const DBusTypeReader  *reader)
760 {
761   return reader->value_pos;
762 }
763
764 dbus_bool_t
765 _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)
766 {
767   dbus_uint32_t array_len;
768
769   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
770   _dbus_assert (!reader->klass->types_only);
771
772   /* reader is supposed to be at an array child */
773 #if RECURSIVE_MARSHAL_READ_TRACE
774    _dbus_verbose ("checking array len at %d\n", reader->value_pos);
775 #endif
776
777    _dbus_marshal_read_basic (reader->value_str,
778                              reader->value_pos,
779                              DBUS_TYPE_UINT32,
780                              &array_len,
781                              reader->byte_order,
782                              NULL);
783 #if RECURSIVE_MARSHAL_READ_TRACE
784   _dbus_verbose (" ... array len = %d\n", array_len);
785 #endif
786
787   return array_len == 0;
788 }
789
790 /**
791  * Get the address of the marshaled value in the data being read.  The
792  * address may not be aligned; you have to align it to the type of the
793  * value you want to read. Most of the demarshal routines do this for
794  * you.
795  *
796  * @param reader the reader
797  * @param value_location the address of the marshaled value
798  */
799 void
800 _dbus_type_reader_read_raw (const DBusTypeReader  *reader,
801                             const unsigned char  **value_location)
802 {
803   _dbus_assert (!reader->klass->types_only);
804
805   *value_location = _dbus_string_get_const_data_len (reader->value_str,
806                                                      reader->value_pos,
807                                                      0);
808 }
809
810 void
811 _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
812                               void                    *value)
813 {
814   int t;
815
816   _dbus_assert (!reader->klass->types_only);
817
818   t = _dbus_type_reader_get_current_type (reader);
819
820   _dbus_marshal_read_basic (reader->value_str,
821                             reader->value_pos,
822                             t, value,
823                             reader->byte_order,
824                             NULL);
825
826
827 #if RECURSIVE_MARSHAL_READ_TRACE
828   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
829                  reader, reader->type_pos, reader->value_pos,
830                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
831 #endif
832 }
833
834 /**
835  * Reads a block of fixed-length basic values, from the current point
836  * in an array to the end of the array.  Does not work for arrays of
837  * string or container types.
838  *
839  * This function returns the array in-place; it does not make a copy,
840  * and it does not swap the bytes.
841  *
842  * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back
843  * and the "value" argument should be a "const double**" and so on.
844  *
845  * @param reader the reader to read from
846  * @param value place to return the array values
847  * @param n_elements place to return number of array elements
848  */
849 void
850 _dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,
851                                     void                  *value,
852                                     int                   *n_elements)
853 {
854   int element_type;
855   int end_pos;
856   int remaining_len;
857   int alignment;
858   int total_len;
859
860   _dbus_assert (!reader->klass->types_only);
861   _dbus_assert (reader->klass == &array_reader_class);
862
863   element_type = first_type_in_signature (reader->type_str,
864                                           reader->type_pos);
865
866   _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
867   _dbus_assert (_dbus_type_is_fixed (element_type));
868
869   alignment = _dbus_type_get_alignment (element_type);
870
871   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
872
873   total_len = array_reader_get_array_len (reader);
874   end_pos = reader->u.array.start_pos + total_len;
875   remaining_len = end_pos - reader->value_pos;
876
877 #if RECURSIVE_MARSHAL_READ_TRACE
878   _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",
879                  end_pos, total_len, remaining_len, reader->value_pos);
880 #endif
881
882   _dbus_assert (remaining_len <= total_len);
883
884   if (remaining_len == 0)
885     *(const DBusBasicValue**) value = NULL;
886   else
887     *(const DBusBasicValue**) value =
888       (void*) _dbus_string_get_const_data_len (reader->value_str,
889                                                reader->value_pos,
890                                                remaining_len);
891
892   *n_elements = remaining_len / alignment;
893   _dbus_assert ((remaining_len % alignment) == 0);
894
895 #if RECURSIVE_MARSHAL_READ_TRACE
896   _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
897                  reader, reader->type_pos, reader->value_pos,
898                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
899 #endif
900 }
901
902 /**
903  * Initialize a new reader pointing to the first type and
904  * corresponding value that's a child of the current container. It's
905  * an error to call this if the current type is a non-container.
906  *
907  * Note that DBusTypeReader traverses values, not types. So if you
908  * have an empty array of array of int, you can't recurse into it. You
909  * can only recurse into each element.
910  *
911  * @param reader the reader
912  * @param sub a reader to init pointing to the first child
913  */
914 void
915 _dbus_type_reader_recurse (DBusTypeReader *reader,
916                            DBusTypeReader *sub)
917 {
918   int t;
919
920   t = first_type_in_signature (reader->type_str, reader->type_pos);
921
922   switch (t)
923     {
924     case DBUS_TYPE_STRUCT:
925       if (reader->klass->types_only)
926         sub->klass = &struct_types_only_reader_class;
927       else
928         sub->klass = &struct_reader_class;
929       break;
930     case DBUS_TYPE_ARRAY:
931       if (reader->klass->types_only)
932         sub->klass = &array_types_only_reader_class;
933       else
934         sub->klass = &array_reader_class;
935       break;
936     case DBUS_TYPE_VARIANT:
937       if (reader->klass->types_only)
938         _dbus_assert_not_reached ("can't recurse into variant typecode");
939       else
940         sub->klass = &variant_reader_class;
941       break;
942     default:
943       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
944 #ifndef DBUS_DISABLE_CHECKS
945       if (t == DBUS_TYPE_INVALID)
946         _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
947 #endif /* DBUS_DISABLE_CHECKS */
948
949       _dbus_assert_not_reached ("don't yet handle recursing into this type");
950     }
951
952   _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
953
954   (* sub->klass->recurse) (sub, reader);
955
956 #if RECURSIVE_MARSHAL_READ_TRACE
957   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
958                  sub, sub->type_pos, sub->value_pos,
959                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
960 #endif
961 }
962
963 /**
964  * Skip to the next value on this "level". e.g. the next field in a
965  * struct, the next value in an array. Returns FALSE at the end of the
966  * current container.
967  *
968  * @param reader the reader
969  * @returns FALSE if nothing more to read at or below this level
970  */
971 dbus_bool_t
972 _dbus_type_reader_next (DBusTypeReader *reader)
973 {
974   int t;
975
976   t = _dbus_type_reader_get_current_type (reader);
977
978 #if RECURSIVE_MARSHAL_READ_TRACE
979   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
980                  reader, reader->type_pos, reader->value_pos,
981                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
982                  _dbus_type_to_string (t));
983 #endif
984
985   if (t == DBUS_TYPE_INVALID)
986     return FALSE;
987
988   (* reader->klass->next) (reader, t);
989
990 #if RECURSIVE_MARSHAL_READ_TRACE
991   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
992                  reader, reader->type_pos, reader->value_pos,
993                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
994                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
995 #endif
996
997   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
998 }
999
1000 /**
1001  * Check whether there's another value on this "level". e.g. the next
1002  * field in a struct, the next value in an array. Returns FALSE at the
1003  * end of the current container.
1004  *
1005  * You probably don't want to use this; it makes for an awkward for/while
1006  * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)"
1007  *
1008  * @param reader the reader
1009  * @returns FALSE if nothing more to read at or below this level
1010  */
1011 dbus_bool_t
1012 _dbus_type_reader_has_next (const DBusTypeReader *reader)
1013 {
1014   /* Not efficient but works for now. */
1015   DBusTypeReader copy;
1016
1017   copy = *reader;
1018   return _dbus_type_reader_next (&copy);
1019 }
1020
1021 /**
1022  * Gets the string and range of said string containing the signature
1023  * of the current value. Essentially a more complete version of
1024  * _dbus_type_reader_get_current_type() (returns the full type
1025  * rather than only the outside of the onion).
1026  *
1027  * Note though that the first byte in a struct signature is
1028  * #DBUS_STRUCT_BEGIN_CHAR while the current type will be
1029  * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the
1030  * signature is always the same as the current type. Another
1031  * difference is that this function will still return a signature when
1032  * inside an empty array; say you recurse into empty array of int32,
1033  * the signature is "i" but the current type will always be
1034  * #DBUS_TYPE_INVALID since there are no elements to be currently
1035  * pointing to.
1036  *
1037  * @param reader the reader
1038  * @param str_p place to return the string with the type in it
1039  * @param start_p place to return start of the type
1040  * @param len_p place to return the length of the type
1041  */
1042 void
1043 _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
1044                                  const DBusString     **str_p,
1045                                  int                   *start_p,
1046                                  int                   *len_p)
1047 {
1048   *str_p = reader->type_str;
1049   *start_p = reader->type_pos;
1050   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
1051 }
1052
1053 typedef struct
1054 {
1055   DBusString replacement;
1056   int padding;
1057 } ReplacementBlock;
1058
1059 static dbus_bool_t
1060 replacement_block_init (ReplacementBlock *block,
1061                         DBusTypeReader   *reader)
1062 {
1063   if (!_dbus_string_init (&block->replacement))
1064     return FALSE;
1065
1066   /* % 8 is the padding to have the same align properties in
1067    * our replacement string as we do at the position being replaced
1068    */
1069   block->padding = reader->value_pos % 8;
1070
1071   if (!_dbus_string_lengthen (&block->replacement, block->padding))
1072     goto oom;
1073
1074   return TRUE;
1075
1076  oom:
1077   _dbus_string_free (&block->replacement);
1078   return FALSE;
1079 }
1080
1081 static dbus_bool_t
1082 replacement_block_replace (ReplacementBlock     *block,
1083                            DBusTypeReader       *reader,
1084                            const DBusTypeReader *realign_root)
1085 {
1086   DBusTypeWriter writer;
1087   DBusTypeReader realign_reader;
1088   DBusList *fixups;
1089   int orig_len;
1090
1091   _dbus_assert (realign_root != NULL);
1092
1093   orig_len = _dbus_string_get_length (&block->replacement);
1094
1095   realign_reader = *realign_root;
1096
1097 #if RECURSIVE_MARSHAL_WRITE_TRACE
1098   _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
1099                  &writer, _dbus_string_get_length (&block->replacement));
1100 #endif
1101   _dbus_type_writer_init_values_only (&writer,
1102                                       realign_reader.byte_order,
1103                                       realign_reader.type_str,
1104                                       realign_reader.type_pos,
1105                                       &block->replacement,
1106                                       _dbus_string_get_length (&block->replacement));
1107
1108   _dbus_assert (realign_reader.value_pos <= reader->value_pos);
1109
1110 #if RECURSIVE_MARSHAL_WRITE_TRACE
1111   _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
1112                  realign_reader.value_pos, &writer, reader->value_pos);
1113 #endif
1114   fixups = NULL;
1115   if (!_dbus_type_writer_write_reader_partial (&writer,
1116                                                &realign_reader,
1117                                                reader,
1118                                                block->padding,
1119                                                _dbus_string_get_length (&block->replacement) - block->padding,
1120                                                &fixups))
1121     goto oom;
1122
1123 #if RECURSIVE_MARSHAL_WRITE_TRACE
1124   _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
1125                  _dbus_string_get_length (&block->replacement) - block->padding);
1126   _dbus_verbose_bytes_of_string (&block->replacement, block->padding,
1127                                  _dbus_string_get_length (&block->replacement) - block->padding);
1128   _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
1129                  reader->value_pos, reader->value_pos % 8,
1130                  realign_reader.value_pos - reader->value_pos,
1131                  realign_reader.value_pos);
1132   _dbus_verbose_bytes_of_string (reader->value_str,
1133                                  reader->value_pos,
1134                                  realign_reader.value_pos - reader->value_pos);
1135 #endif
1136
1137   /* Move the replacement into position
1138    * (realign_reader should now be at the end of the block to be replaced)
1139    */
1140   if (!_dbus_string_replace_len (&block->replacement, block->padding,
1141                                  _dbus_string_get_length (&block->replacement) - block->padding,
1142                                  (DBusString*) reader->value_str,
1143                                  reader->value_pos,
1144                                  realign_reader.value_pos - reader->value_pos))
1145     goto oom;
1146
1147   /* Process our fixups now that we can't have an OOM error */
1148   apply_and_free_fixups (&fixups, reader);
1149
1150   return TRUE;
1151
1152  oom:
1153   _dbus_string_set_length (&block->replacement, orig_len);
1154   free_fixups (&fixups);
1155   return FALSE;
1156 }
1157
1158 static void
1159 replacement_block_free (ReplacementBlock *block)
1160 {
1161   _dbus_string_free (&block->replacement);
1162 }
1163
1164 /* In the variable-length case, we have to fix alignment after we insert.
1165  * The strategy is as follows:
1166  *
1167  *  - pad a new string to have the same alignment as the
1168  *    start of the current basic value
1169  *  - write the new basic value
1170  *  - copy from the original reader to the new string,
1171  *    which will fix the alignment of types following
1172  *    the new value
1173  *    - this copy has to start at realign_root,
1174  *      but not really write anything until it
1175  *      passes the value being set
1176  *    - as an optimization, we can stop copying
1177  *      when the source and dest values are both
1178  *      on an 8-boundary, since we know all following
1179  *      padding and alignment will be identical
1180  *  - copy the new string back to the original
1181  *    string, replacing the relevant part of the
1182  *    original string
1183  *  - now any arrays in the original string that
1184  *    contained the replaced string may have the
1185  *    wrong length; so we have to fix that
1186  */
1187 static dbus_bool_t
1188 reader_set_basic_variable_length (DBusTypeReader       *reader,
1189                                   int                   current_type,
1190                                   const void           *value,
1191                                   const DBusTypeReader *realign_root)
1192 {
1193   dbus_bool_t retval;
1194   ReplacementBlock block;
1195   DBusTypeWriter writer;
1196
1197   _dbus_assert (realign_root != NULL);
1198
1199   retval = FALSE;
1200
1201   if (!replacement_block_init (&block, reader))
1202     return FALSE;
1203
1204   /* Write the new basic value */
1205 #if RECURSIVE_MARSHAL_WRITE_TRACE
1206   _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
1207                  &writer, _dbus_string_get_length (&block.replacement));
1208 #endif
1209   _dbus_type_writer_init_values_only (&writer,
1210                                       reader->byte_order,
1211                                       reader->type_str,
1212                                       reader->type_pos,
1213                                       &block.replacement,
1214                                       _dbus_string_get_length (&block.replacement));
1215 #if RECURSIVE_MARSHAL_WRITE_TRACE
1216   _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
1217 #endif
1218   if (!_dbus_type_writer_write_basic (&writer, current_type, value))
1219     goto out;
1220
1221   if (!replacement_block_replace (&block,
1222                                   reader,
1223                                   realign_root))
1224     goto out;
1225
1226   retval = TRUE;
1227
1228  out:
1229   replacement_block_free (&block);
1230   return retval;
1231 }
1232
1233 static void
1234 reader_set_basic_fixed_length (DBusTypeReader *reader,
1235                                int             current_type,
1236                                const void     *value)
1237 {
1238   _dbus_marshal_set_basic ((DBusString*) reader->value_str,
1239                            reader->value_pos,
1240                            current_type,
1241                            value,
1242                            reader->byte_order,
1243                            NULL, NULL);
1244 }
1245
1246 /**
1247  * Sets a new value for the basic type value pointed to by the reader,
1248  * leaving the reader valid to continue reading. Any other readers
1249  * will be invalidated if you set a variable-length type such as a
1250  * string.
1251  *
1252  * The provided realign_root is the reader to start from when
1253  * realigning the data that follows the newly-set value. The reader
1254  * parameter must point to a value below the realign_root parameter.
1255  * If the type being set is fixed-length, then realign_root may be
1256  * #NULL. Only values reachable from realign_root will be realigned,
1257  * so if your string contains other values you will need to deal with
1258  * those somehow yourself. It is OK if realign_root is the same
1259  * reader as the reader parameter, though if you aren't setting the
1260  * root it may not be such a good idea.
1261  *
1262  * @todo DBusTypeReader currently takes "const" versions of the type
1263  * and value strings, and this function modifies those strings by
1264  * casting away the const, which is of course bad if we want to get
1265  * picky. (To be truly clean you'd have an object which contained the
1266  * type and value strings and set_basic would be a method on that
1267  * object... this would also make DBusTypeReader the same thing as
1268  * DBusTypeMark. But since DBusMessage is effectively that object for
1269  * D-BUS it doesn't seem worth creating some random object.)
1270  *
1271  * @todo optimize this by only rewriting until the old and new values
1272  * are at the same alignment. Frequently this should result in only
1273  * replacing the value that's immediately at hand.
1274  *
1275  * @param reader reader indicating where to set a new value
1276  * @param value address of the value to set
1277  * @param realign_root realign from here
1278  * @returns #FALSE if not enough memory
1279  */
1280 dbus_bool_t
1281 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
1282                              const void           *value,
1283                              const DBusTypeReader *realign_root)
1284 {
1285   int current_type;
1286
1287   _dbus_assert (!reader->klass->types_only);
1288   _dbus_assert (reader->value_str == realign_root->value_str);
1289   _dbus_assert (reader->value_pos >= realign_root->value_pos);
1290
1291   current_type = _dbus_type_reader_get_current_type (reader);
1292
1293 #if RECURSIVE_MARSHAL_WRITE_TRACE
1294   _dbus_verbose ("  SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",
1295                  reader, reader->type_pos, reader->value_pos,
1296                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1297                  realign_root,
1298                  realign_root ? realign_root->value_pos : -1,
1299                  _dbus_type_to_string (current_type));
1300   _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
1301                                  _dbus_string_get_length (realign_root->value_str) -
1302                                  realign_root->value_pos);
1303 #endif
1304
1305   _dbus_assert (_dbus_type_is_basic (current_type));
1306
1307   if (_dbus_type_is_fixed (current_type))
1308     {
1309       reader_set_basic_fixed_length (reader, current_type, value);
1310       return TRUE;
1311     }
1312   else
1313     {
1314       _dbus_assert (realign_root != NULL);
1315       return reader_set_basic_variable_length (reader, current_type,
1316                                                value, realign_root);
1317     }
1318 }
1319
1320 /**
1321  * Recursively deletes any value pointed to by the reader, leaving the
1322  * reader valid to continue reading. Any other readers will be
1323  * invalidated.
1324  *
1325  * The provided realign_root is the reader to start from when
1326  * realigning the data that follows the newly-set value.
1327  * See _dbus_type_reader_set_basic() for more details on the
1328  * realign_root paramter.
1329  *
1330  * @todo for now this does not delete the typecodes associated with
1331  * the value, so this function should only be used for array elements.
1332  *
1333  * @param reader reader indicating where to delete a value
1334  * @param realign_root realign from here
1335  * @returns #FALSE if not enough memory
1336  */
1337 dbus_bool_t
1338 _dbus_type_reader_delete (DBusTypeReader        *reader,
1339                           const DBusTypeReader  *realign_root)
1340 {
1341   dbus_bool_t retval;
1342   ReplacementBlock block;
1343
1344   _dbus_assert (realign_root != NULL);
1345   _dbus_assert (reader->klass == &array_reader_class);
1346
1347   retval = FALSE;
1348
1349   if (!replacement_block_init (&block, reader))
1350     return FALSE;
1351
1352   if (!replacement_block_replace (&block,
1353                                   reader,
1354                                   realign_root))
1355     goto out;
1356
1357   retval = TRUE;
1358
1359  out:
1360   replacement_block_free (&block);
1361   return retval;
1362 }
1363
1364 /**
1365  * Compares two readers, which must be iterating over the same value data.
1366  * Returns #TRUE if the first parameter is further along than the second parameter.
1367  *
1368  * @param lhs left-hand-side (first) parameter
1369  * @param rhs left-hand-side (first) parameter
1370  * @returns whether lhs is greater than rhs
1371  */
1372 dbus_bool_t
1373 _dbus_type_reader_greater_than (const DBusTypeReader  *lhs,
1374                                 const DBusTypeReader  *rhs)
1375 {
1376   _dbus_assert (lhs->value_str == rhs->value_str);
1377
1378   return lhs->value_pos > rhs->value_pos;
1379 }
1380
1381 /*
1382  *
1383  *
1384  *         DBusTypeWriter
1385  *
1386  *
1387  *
1388  */
1389
1390 /**
1391  * Initialize a write iterator, which is used to write out values in
1392  * serialized D-BUS format.
1393  *
1394  * The type_pos passed in is expected to be inside an already-valid,
1395  * though potentially empty, type signature. This means that the byte
1396  * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
1397  * other valid type. #DBusTypeWriter won't enforce that the signature
1398  * is already valid (you can append the nul byte at the end if you
1399  * like), but just be aware that you need the nul byte eventually and
1400  * #DBusTypeWriter isn't going to write it for you.
1401  *
1402  * @param writer the writer to init
1403  * @param byte_order the byte order to marshal into
1404  * @param type_str the string to write typecodes into
1405  * @param type_pos where to insert typecodes
1406  * @param value_str the string to write values into
1407  * @param value_pos where to insert values
1408  *
1409  */
1410 void
1411 _dbus_type_writer_init (DBusTypeWriter *writer,
1412                         int             byte_order,
1413                         DBusString     *type_str,
1414                         int             type_pos,
1415                         DBusString     *value_str,
1416                         int             value_pos)
1417 {
1418   writer->byte_order = byte_order;
1419   writer->type_str = type_str;
1420   writer->type_pos = type_pos;
1421   writer->value_str = value_str;
1422   writer->value_pos = value_pos;
1423   writer->container_type = DBUS_TYPE_INVALID;
1424   writer->type_pos_is_expectation = FALSE;
1425   writer->enabled = TRUE;
1426
1427 #if RECURSIVE_MARSHAL_WRITE_TRACE
1428   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1429                  writer->type_str ?
1430                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1431                  "unknown");
1432 #endif
1433 }
1434
1435 /**
1436  * Initialize a write iterator, with the signature to be provided
1437  * later.
1438  *
1439  * @param writer the writer to init
1440  * @param byte_order the byte order to marshal into
1441  * @param value_str the string to write values into
1442  * @param value_pos where to insert values
1443  *
1444  */
1445 void
1446 _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer,
1447                                       int             byte_order,
1448                                       DBusString     *value_str,
1449                                       int             value_pos)
1450 {
1451   _dbus_type_writer_init (writer, byte_order,
1452                           NULL, 0, value_str, value_pos);
1453 }
1454
1455 /**
1456  * Adds type string to the writer, if it had none.
1457  *
1458  * @param writer the writer to init
1459  * @param type_str type string to add
1460  * @param type_pos type position
1461  *
1462  */
1463 void
1464 _dbus_type_writer_add_types (DBusTypeWriter *writer,
1465                              DBusString     *type_str,
1466                              int             type_pos)
1467 {
1468   if (writer->type_str == NULL) /* keeps us from using this as setter */
1469     {
1470       writer->type_str = type_str;
1471       writer->type_pos = type_pos;
1472     }
1473 }
1474
1475 /**
1476  * Removes type string from the writer.
1477  *
1478  * @param writer the writer to remove from
1479  */
1480 void
1481 _dbus_type_writer_remove_types (DBusTypeWriter *writer)
1482 {
1483   writer->type_str = NULL;
1484   writer->type_pos = -1;
1485 }
1486
1487 /**
1488  * Like _dbus_type_writer_init(), except the type string
1489  * passed in should correspond to an existing signature that
1490  * matches what you're going to write out. The writer will
1491  * check what you write vs. this existing signature.
1492  *
1493  * @param writer the writer to init
1494  * @param byte_order the byte order to marshal into
1495  * @param type_str the string with signature
1496  * @param type_pos start of signature
1497  * @param value_str the string to write values into
1498  * @param value_pos where to insert values
1499  *
1500  */
1501 void
1502 _dbus_type_writer_init_values_only (DBusTypeWriter   *writer,
1503                                     int               byte_order,
1504                                     const DBusString *type_str,
1505                                     int               type_pos,
1506                                     DBusString       *value_str,
1507                                     int               value_pos)
1508 {
1509   _dbus_type_writer_init (writer, byte_order,
1510                           (DBusString*)type_str, type_pos,
1511                           value_str, value_pos);
1512
1513   writer->type_pos_is_expectation = TRUE;
1514 }
1515
1516 static dbus_bool_t
1517 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1518                                            int             type,
1519                                            const void     *value)
1520 {
1521   if (writer->enabled)
1522     return _dbus_marshal_write_basic (writer->value_str,
1523                                       writer->value_pos,
1524                                       type,
1525                                       value,
1526                                       writer->byte_order,
1527                                       &writer->value_pos);
1528   else
1529     return TRUE;
1530 }
1531
1532 /* If our parent is an array, things are a little bit complicated.
1533  *
1534  * The parent must have a complete element type, such as
1535  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1536  * unclosed parens, or an "a" with no following type.
1537  *
1538  * To recurse, the only allowed operation is to recurse into the
1539  * first type in the element type. So for "i" you can't recurse, for
1540  * "ai" you can recurse into the array, for "(ii)" you can recurse
1541  * into the struct.
1542  *
1543  * If you recurse into the array for "ai", then you must specify
1544  * "i" for the element type of the array you recurse into.
1545  *
1546  * While inside an array at any level, we need to avoid writing to
1547  * type_str, since the type only appears once for the whole array,
1548  * it does not appear for each array element.
1549  *
1550  * While inside an array type_pos points to the expected next
1551  * typecode, rather than the next place we could write a typecode.
1552  */
1553 static void
1554 writer_recurse_init_and_check (DBusTypeWriter *writer,
1555                                int             container_type,
1556                                DBusTypeWriter *sub)
1557 {
1558   _dbus_type_writer_init (sub,
1559                           writer->byte_order,
1560                           writer->type_str,
1561                           writer->type_pos,
1562                           writer->value_str,
1563                           writer->value_pos);
1564
1565   sub->container_type = container_type;
1566
1567   if (writer->type_pos_is_expectation ||
1568       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
1569     sub->type_pos_is_expectation = TRUE;
1570   else
1571     sub->type_pos_is_expectation = FALSE;
1572
1573   sub->enabled = writer->enabled;
1574
1575 #ifndef DBUS_DISABLE_CHECKS
1576   if (writer->type_pos_is_expectation && writer->type_str)
1577     {
1578       int expected;
1579
1580       expected = first_type_in_signature (writer->type_str, writer->type_pos);
1581
1582       if (expected != sub->container_type)
1583         {
1584           _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
1585                       _dbus_type_to_string (sub->container_type),
1586                       _dbus_type_to_string (expected));
1587           _dbus_assert_not_reached ("bad array element or variant content written");
1588         }
1589     }
1590 #endif /* DBUS_DISABLE_CHECKS */
1591
1592 #if RECURSIVE_MARSHAL_WRITE_TRACE
1593   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
1594                  writer,
1595                  _dbus_type_to_string (writer->container_type),
1596                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1597                  writer->type_str ?
1598                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1599                  "unknown",
1600                  writer->enabled);
1601   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
1602                  sub,
1603                  _dbus_type_to_string (sub->container_type),
1604                  sub->type_pos, sub->value_pos,
1605                  sub->type_pos_is_expectation,
1606                  sub->enabled);
1607 #endif
1608 }
1609
1610 static dbus_bool_t
1611 write_or_verify_typecode (DBusTypeWriter *writer,
1612                           int             typecode)
1613 {
1614   /* A subwriter inside an array or variant will have type_pos
1615    * pointing to the expected typecode; a writer not inside an array
1616    * or variant has type_pos pointing to the next place to insert a
1617    * typecode.
1618    */
1619 #if RECURSIVE_MARSHAL_WRITE_TRACE
1620   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
1621                  writer, writer->type_pos,
1622                  writer->type_str ?
1623                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1624                  "unknown",
1625                  writer->enabled);
1626 #endif
1627
1628   if (writer->type_str == NULL)
1629     return TRUE;
1630
1631   if (writer->type_pos_is_expectation)
1632     {
1633 #ifndef DBUS_DISABLE_CHECKS
1634       {
1635         int expected;
1636
1637         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1638
1639         if (expected != typecode)
1640           {
1641             _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1642                         _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1643             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1644           }
1645       }
1646 #endif /* DBUS_DISABLE_CHECKS */
1647
1648       /* if immediately inside an array we'd always be appending an element,
1649        * so the expected type doesn't change; if inside a struct or something
1650        * below an array, we need to move through said struct or something.
1651        */
1652       if (writer->container_type != DBUS_TYPE_ARRAY)
1653         writer->type_pos += 1;
1654     }
1655   else
1656     {
1657       if (!_dbus_string_insert_byte (writer->type_str,
1658                                      writer->type_pos,
1659                                      typecode))
1660         return FALSE;
1661
1662       writer->type_pos += 1;
1663     }
1664
1665 #if RECURSIVE_MARSHAL_WRITE_TRACE
1666   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1667                  writer, writer->type_pos,
1668                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1669 #endif
1670
1671   return TRUE;
1672 }
1673
1674 static dbus_bool_t
1675 writer_recurse_struct (DBusTypeWriter   *writer,
1676                        const DBusString *contained_type,
1677                        int               contained_type_start,
1678                        int               contained_type_len,
1679                        DBusTypeWriter   *sub)
1680 {
1681   /* FIXME right now contained_type is ignored; we could probably
1682    * almost trivially fix the code so if it's present we
1683    * write it out and then set type_pos_is_expectation
1684    */
1685
1686   /* Ensure that we'll be able to add alignment padding and the typecode */
1687   if (writer->enabled)
1688     {
1689       if (!_dbus_string_alloc_space (sub->value_str, 8))
1690         return FALSE;
1691     }
1692
1693   if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1694     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1695
1696   if (writer->enabled)
1697     {
1698       if (!_dbus_string_insert_bytes (sub->value_str,
1699                                       sub->value_pos,
1700                                       _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1701                                       '\0'))
1702         _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1703       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1704     }
1705
1706   return TRUE;
1707 }
1708
1709
1710 static dbus_bool_t
1711 writer_recurse_array (DBusTypeWriter   *writer,
1712                       const DBusString *contained_type,
1713                       int               contained_type_start,
1714                       int               contained_type_len,
1715                       DBusTypeWriter   *sub,
1716                       dbus_bool_t       is_array_append)
1717 {
1718   dbus_uint32_t value = 0;
1719   int alignment;
1720   int aligned;
1721
1722 #ifndef DBUS_DISABLE_CHECKS
1723   if (writer->container_type == DBUS_TYPE_ARRAY &&
1724       writer->type_str)
1725     {
1726       if (!_dbus_string_equal_substring (contained_type,
1727                                          contained_type_start,
1728                                          contained_type_len,
1729                                          writer->type_str,
1730                                          writer->u.array.element_type_pos + 1))
1731         {
1732           _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1733                       _dbus_string_get_const_data_len (contained_type,
1734                                                        contained_type_start,
1735                                                        contained_type_len));
1736           _dbus_assert_not_reached ("incompatible type for child array");
1737         }
1738     }
1739 #endif /* DBUS_DISABLE_CHECKS */
1740
1741   if (writer->enabled && !is_array_append)
1742     {
1743       /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1744        * before array values
1745        */
1746       if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1747         return FALSE;
1748     }
1749
1750   if (writer->type_str != NULL)
1751     {
1752       sub->type_pos += 1; /* move to point to the element type, since type_pos
1753                            * should be the expected type for further writes
1754                            */
1755       sub->u.array.element_type_pos = sub->type_pos;
1756     }
1757
1758   if (!writer->type_pos_is_expectation)
1759     {
1760       /* sub is a toplevel/outermost array so we need to write the type data */
1761
1762       /* alloc space for array typecode, element signature */
1763       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1764         return FALSE;
1765
1766       if (!_dbus_string_insert_byte (writer->type_str,
1767                                      writer->type_pos,
1768                                      DBUS_TYPE_ARRAY))
1769         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1770
1771       if (!_dbus_string_copy_len (contained_type,
1772                                   contained_type_start, contained_type_len,
1773                                   sub->type_str,
1774                                   sub->u.array.element_type_pos))
1775         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1776     }
1777
1778   if (writer->type_str != NULL)
1779     {
1780       /* If the parent is an array, we hold type_pos pointing at the array element type;
1781        * otherwise advance it to reflect the array value we just recursed into
1782        */
1783       if (writer->container_type != DBUS_TYPE_ARRAY)
1784         writer->type_pos += 1 + contained_type_len;
1785       else
1786         _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1787     }
1788
1789   if (writer->enabled)
1790     {
1791       /* Write (or jump over, if is_array_append) the length */
1792       sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1793
1794       if (is_array_append)
1795         {
1796           sub->value_pos += 4;
1797         }
1798       else
1799         {
1800           if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1801                                                           &value))
1802             _dbus_assert_not_reached ("should not have failed to insert array len");
1803         }
1804
1805       _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1806
1807       /* Write alignment padding for array elements
1808        * Note that we write the padding *even for empty arrays*
1809        * to avoid wonky special cases
1810        */
1811       alignment = element_type_get_alignment (contained_type, contained_type_start);
1812
1813       aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1814       if (aligned != sub->value_pos)
1815         {
1816           if (!is_array_append)
1817             {
1818               if (!_dbus_string_insert_bytes (sub->value_str,
1819                                               sub->value_pos,
1820                                               aligned - sub->value_pos,
1821                                               '\0'))
1822                 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1823             }
1824
1825           sub->value_pos = aligned;
1826         }
1827
1828       sub->u.array.start_pos = sub->value_pos;
1829
1830       if (is_array_append)
1831         {
1832           dbus_uint32_t len;
1833
1834           len = _dbus_marshal_read_uint32 (sub->value_str,
1835                                            sub->u.array.len_pos,
1836                                            sub->byte_order, NULL);
1837
1838           sub->value_pos += len;
1839         }
1840     }
1841   else
1842     {
1843       /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
1844       sub->u.array.len_pos = -1;
1845       sub->u.array.start_pos = sub->value_pos;
1846     }
1847
1848   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1849   _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
1850
1851 #if RECURSIVE_MARSHAL_WRITE_TRACE
1852       _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
1853                      sub->type_str ?
1854                      _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
1855                      "unknown",
1856                      sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
1857 #endif
1858
1859   return TRUE;
1860 }
1861
1862 /* Variant value will normally have:
1863  *   1 byte signature length not including nul
1864  *   signature typecodes (nul terminated)
1865  *   padding to 8-boundary
1866  *   body according to signature
1867  *
1868  * The signature string can only have a single type
1869  * in it but that type may be complex/recursive.
1870  *
1871  * So a typical variant type with the integer 3 will have these
1872  * octets:
1873  *   0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1874  *
1875  * For an array of 4-byte types stuffed into variants, the padding to
1876  * 8-boundary is only the 1 byte that is required for the 4-boundary
1877  * anyhow for all array elements after the first one. And for single
1878  * variants in isolation, wasting a few bytes is hardly a big deal.
1879  *
1880  * The main world of hurt for writing out a variant is that the type
1881  * string is the same string as the value string. Which means
1882  * inserting to the type string will move the value_pos; and it means
1883  * that inserting to the type string could break type alignment.
1884  *
1885  * This type alignment issue is why the body of the variant is always
1886  * 8-aligned. Then we know that re-8-aligning the start of the body
1887  * will always correctly align the full contents of the variant type.
1888  */
1889 static dbus_bool_t
1890 writer_recurse_variant (DBusTypeWriter   *writer,
1891                         const DBusString *contained_type,
1892                         int               contained_type_start,
1893                         int               contained_type_len,
1894                         DBusTypeWriter   *sub)
1895 {
1896   if (writer->enabled)
1897     {
1898       /* Allocate space for the worst case, which is 1 byte sig
1899        * length, nul byte at end of sig, and 7 bytes padding to
1900        * 8-boundary.
1901        */
1902       if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1903         return FALSE;
1904     }
1905
1906   /* write VARIANT typecode to the parent's type string */
1907   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1908     return FALSE;
1909
1910   /* If not enabled, mark that we have no type_str anymore ... */
1911
1912   if (!writer->enabled)
1913     {
1914       sub->type_str = NULL;
1915       sub->type_pos = -1;
1916
1917       return TRUE;
1918     }
1919
1920   /* If we're enabled then continue ... */
1921
1922   if (!_dbus_string_insert_byte (sub->value_str,
1923                                  sub->value_pos,
1924                                  contained_type_len))
1925     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1926
1927   sub->value_pos += 1;
1928
1929   /* Here we switch over to the expected type sig we're about to write */
1930   sub->type_str = sub->value_str;
1931   sub->type_pos = sub->value_pos;
1932
1933   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
1934                               sub->value_str, sub->value_pos))
1935     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1936
1937   sub->value_pos += contained_type_len;
1938
1939   if (!_dbus_string_insert_byte (sub->value_str,
1940                                  sub->value_pos,
1941                                  DBUS_TYPE_INVALID))
1942     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1943
1944   sub->value_pos += 1;
1945
1946   if (!_dbus_string_insert_bytes (sub->value_str,
1947                                   sub->value_pos,
1948                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1949                                   '\0'))
1950     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1951   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1952
1953   return TRUE;
1954 }
1955
1956 static dbus_bool_t
1957 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
1958                                          int               container_type,
1959                                          const DBusString *contained_type,
1960                                          int               contained_type_start,
1961                                          int               contained_type_len,
1962                                          DBusTypeWriter   *sub,
1963                                          dbus_bool_t       is_array_append)
1964 {
1965   writer_recurse_init_and_check (writer, container_type, sub);
1966
1967   switch (container_type)
1968     {
1969     case DBUS_TYPE_STRUCT:
1970       return writer_recurse_struct (writer,
1971                                     contained_type, contained_type_start, contained_type_len,
1972                                     sub);
1973       break;
1974     case DBUS_TYPE_ARRAY:
1975       return writer_recurse_array (writer,
1976                                    contained_type, contained_type_start, contained_type_len,
1977                                    sub, is_array_append);
1978       break;
1979     case DBUS_TYPE_VARIANT:
1980       return writer_recurse_variant (writer,
1981                                      contained_type, contained_type_start, contained_type_len,
1982                                      sub);
1983       break;
1984     default:
1985       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
1986       return FALSE;
1987       break;
1988     }
1989 }
1990
1991 dbus_bool_t
1992 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
1993                            int               container_type,
1994                            const DBusString *contained_type,
1995                            int               contained_type_start,
1996                            DBusTypeWriter   *sub)
1997 {
1998   int contained_type_len;
1999
2000   if (contained_type)
2001     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2002   else
2003     contained_type_len = 0;
2004
2005   return _dbus_type_writer_recurse_contained_len (writer, container_type,
2006                                                   contained_type,
2007                                                   contained_type_start,
2008                                                   contained_type_len,
2009                                                   sub,
2010                                                   FALSE);
2011 }
2012
2013 /**
2014  * Append to an existing array. Essentially, the writer will read an
2015  * existing length at the write location; jump over that length; and
2016  * write new fields. On unrecurse(), the existing length will be
2017  * updated.
2018  *
2019  * @param writer the writer
2020  * @param contained_type element type
2021  * @param contained_type_start position of element type
2022  * @param sub the subwriter to init
2023  * @returns #FALSE if no memory
2024  */
2025 dbus_bool_t
2026 _dbus_type_writer_append_array (DBusTypeWriter   *writer,
2027                                 const DBusString *contained_type,
2028                                 int               contained_type_start,
2029                                 DBusTypeWriter   *sub)
2030 {
2031   int contained_type_len;
2032
2033   if (contained_type)
2034     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2035   else
2036     contained_type_len = 0;
2037
2038   return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
2039                                                   contained_type,
2040                                                   contained_type_start,
2041                                                   contained_type_len,
2042                                                   sub,
2043                                                   TRUE);
2044 }
2045
2046 static int
2047 writer_get_array_len (DBusTypeWriter *writer)
2048 {
2049   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
2050   return writer->value_pos - writer->u.array.start_pos;
2051 }
2052
2053 dbus_bool_t
2054 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
2055                              DBusTypeWriter *sub)
2056 {
2057   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
2058   _dbus_assert (!writer->type_pos_is_expectation ||
2059                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
2060
2061 #if RECURSIVE_MARSHAL_WRITE_TRACE
2062   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2063                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2064                  _dbus_type_to_string (writer->container_type));
2065   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2066                  sub, sub->type_pos, sub->value_pos,
2067                  sub->type_pos_is_expectation,
2068                  _dbus_type_to_string (sub->container_type));
2069 #endif
2070
2071   if (sub->container_type == DBUS_TYPE_STRUCT)
2072     {
2073       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
2074         return FALSE;
2075     }
2076   else if (sub->container_type == DBUS_TYPE_ARRAY)
2077     {
2078       if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
2079         {
2080           dbus_uint32_t len;
2081
2082           /* Set the array length */
2083           len = writer_get_array_len (sub);
2084           _dbus_marshal_set_uint32 (sub->value_str,
2085                                     sub->u.array.len_pos,
2086                                     len,
2087                                     sub->byte_order);
2088 #if RECURSIVE_MARSHAL_WRITE_TRACE
2089           _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
2090                          len, sub->u.array.len_pos);
2091 #endif
2092         }
2093 #if RECURSIVE_MARSHAL_WRITE_TRACE
2094       else
2095         {
2096           _dbus_verbose ("    not filling in sub array len because we were disabled when we passed the len\n");
2097         }
2098 #endif
2099     }
2100
2101   /* Now get type_pos right for the parent writer. Here are the cases:
2102    *
2103    * Cases !writer->type_pos_is_expectation:
2104    *   (in these cases we want to update to the new insertion point)
2105    *
2106    * - if we recursed into a STRUCT then we didn't know in advance
2107    *   what the types in the struct would be; so we have to fill in
2108    *   that information now.
2109    *       writer->type_pos = sub->type_pos
2110    *
2111    * - if we recursed into anything else, we knew the full array
2112    *   type, or knew the single typecode marking VARIANT, so
2113    *   writer->type_pos is already correct.
2114    *       writer->type_pos should remain as-is
2115    *
2116    * - note that the parent is never an ARRAY or VARIANT, if it were
2117    *   then type_pos_is_expectation would be TRUE. The parent
2118    *   is thus known to be a toplevel or STRUCT.
2119    *
2120    * Cases where writer->type_pos_is_expectation:
2121    *   (in these cases we want to update to next expected type to write)
2122    *
2123    * - we recursed from STRUCT into STRUCT and we didn't increment
2124    *   type_pos in the parent just to stay consistent with the
2125    *   !writer->type_pos_is_expectation case (though we could
2126    *   special-case this in recurse_struct instead if we wanted)
2127    *       writer->type_pos = sub->type_pos
2128    *
2129    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
2130    *   for parent should have been incremented already
2131    *       writer->type_pos should remain as-is
2132    *
2133    * - we recursed from ARRAY into a sub-element, so type_pos in the
2134    *   parent is the element type and should remain the element type
2135    *   for the benefit of the next child element
2136    *       writer->type_pos should remain as-is
2137    *
2138    * - we recursed from VARIANT into its value, so type_pos in the
2139    *   parent makes no difference since there's only one value
2140    *   and we just finished writing it and won't use type_pos again
2141    *       writer->type_pos should remain as-is
2142    */
2143   if (writer->type_str != NULL)
2144     {
2145       if (sub->container_type == DBUS_TYPE_STRUCT &&
2146           (writer->container_type == DBUS_TYPE_STRUCT ||
2147            writer->container_type == DBUS_TYPE_INVALID))
2148         {
2149           /* Advance the parent to the next struct field */
2150           writer->type_pos = sub->type_pos;
2151         }
2152     }
2153
2154   writer->value_pos = sub->value_pos;
2155
2156 #if RECURSIVE_MARSHAL_WRITE_TRACE
2157   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
2158                  writer, writer->type_pos, writer->value_pos,
2159                  writer->type_str ?
2160                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
2161                  "unknown");
2162 #endif
2163
2164   return TRUE;
2165 }
2166
2167 dbus_bool_t
2168 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
2169                                int             type,
2170                                const void     *value)
2171 {
2172   dbus_bool_t retval;
2173
2174   /* First ensure that our type realloc will succeed */
2175   if (!writer->type_pos_is_expectation && writer->type_str != NULL)
2176     {
2177       if (!_dbus_string_alloc_space (writer->type_str, 1))
2178         return FALSE;
2179     }
2180
2181   retval = FALSE;
2182
2183   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
2184     goto out;
2185
2186   if (!write_or_verify_typecode (writer, type))
2187     _dbus_assert_not_reached ("failed to write typecode after prealloc");
2188
2189   retval = TRUE;
2190
2191  out:
2192 #if RECURSIVE_MARSHAL_WRITE_TRACE
2193   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
2194                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2195                  writer->enabled);
2196 #endif
2197
2198   return retval;
2199 }
2200
2201 /**
2202  * Writes a block of fixed-length basic values, i.e. those that are
2203  * both _dbus_type_is_fixed() and _dbus_type_is_basic(). The block
2204  * must be written inside an array.
2205  *
2206  * The value parameter should be the address of said array of values,
2207  * so e.g. if it's an array of double, pass in "const double**"
2208  *
2209  * @param writer the writer
2210  * @param element_type type of stuff in the array
2211  * @param value address of the array
2212  * @param n_elements number of elements in the array
2213  * @returns #FALSE if no memory
2214  */
2215 dbus_bool_t
2216 _dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,
2217                                      int                    element_type,
2218                                      const void            *value,
2219                                      int                    n_elements)
2220 {
2221   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
2222   _dbus_assert (_dbus_type_is_fixed (element_type));
2223   _dbus_assert (writer->type_pos_is_expectation);
2224   _dbus_assert (n_elements >= 0);
2225
2226 #if RECURSIVE_MARSHAL_WRITE_TRACE
2227   _dbus_verbose ("  type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",
2228                  writer, writer->type_pos, writer->value_pos, n_elements);
2229 #endif
2230
2231   if (!write_or_verify_typecode (writer, element_type))
2232     _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
2233
2234   if (writer->enabled)
2235     {
2236       if (!_dbus_marshal_write_fixed_multi (writer->value_str,
2237                                             writer->value_pos,
2238                                             element_type,
2239                                             value,
2240                                             n_elements,
2241                                             writer->byte_order,
2242                                             &writer->value_pos))
2243         return FALSE;
2244     }
2245
2246 #if RECURSIVE_MARSHAL_WRITE_TRACE
2247   _dbus_verbose ("  type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",
2248                  writer, writer->type_pos, writer->value_pos, n_elements);
2249 #endif
2250
2251   return TRUE;
2252 }
2253
2254 static void
2255 enable_if_after (DBusTypeWriter       *writer,
2256                  DBusTypeReader       *reader,
2257                  const DBusTypeReader *start_after)
2258 {
2259   if (start_after)
2260     {
2261       if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))
2262         {
2263           _dbus_type_writer_set_enabled (writer, TRUE);
2264 #if RECURSIVE_MARSHAL_WRITE_TRACE
2265           _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",
2266                          writer, writer->value_pos, reader->value_pos, start_after->value_pos);
2267 #endif
2268         }
2269
2270       _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||
2271                     (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));
2272     }
2273 }
2274
2275 static dbus_bool_t
2276 append_fixup (DBusList               **fixups,
2277               const DBusArrayLenFixup *fixup)
2278 {
2279   DBusArrayLenFixup *f;
2280
2281   f = dbus_new (DBusArrayLenFixup, 1);
2282   if (f == NULL)
2283     return FALSE;
2284
2285   *f = *fixup;
2286
2287   if (!_dbus_list_append (fixups, f))
2288     {
2289       dbus_free (f);
2290       return FALSE;
2291     }
2292
2293   _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader);
2294   _dbus_assert (f->new_len == fixup->new_len);
2295
2296   return TRUE;
2297 }
2298
2299 /* This loop is trivial if you ignore all the start_after nonsense,
2300  * so if you're trying to figure it out, start by ignoring that
2301  */
2302 static dbus_bool_t
2303 writer_write_reader_helper (DBusTypeWriter       *writer,
2304                             DBusTypeReader       *reader,
2305                             const DBusTypeReader *start_after,
2306                             int                   start_after_new_pos,
2307                             int                   start_after_new_len,
2308                             DBusList            **fixups,
2309                             dbus_bool_t           inside_start_after)
2310 {
2311   int current_type;
2312
2313   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
2314     {
2315       if (_dbus_type_is_container (current_type))
2316         {
2317           DBusTypeReader subreader;
2318           DBusTypeWriter subwriter;
2319           const DBusString *sig_str;
2320           int sig_start;
2321           int sig_len;
2322           dbus_bool_t enabled_at_recurse;
2323           dbus_bool_t past_start_after;
2324           int reader_array_len_pos;
2325           int reader_array_start_pos;
2326           dbus_bool_t this_is_start_after;
2327
2328           /* type_pos is checked since e.g. in a struct the struct
2329            * and its first field have the same value_pos.
2330            * type_str will differ in reader/start_after for variants
2331            * where type_str is inside the value_str
2332            */
2333           if (!inside_start_after && start_after &&
2334               reader->value_pos == start_after->value_pos &&
2335               reader->type_str == start_after->type_str &&
2336               reader->type_pos == start_after->type_pos)
2337             this_is_start_after = TRUE;
2338           else
2339             this_is_start_after = FALSE;
2340
2341           _dbus_type_reader_recurse (reader, &subreader);
2342
2343           if (current_type == DBUS_TYPE_ARRAY)
2344             {
2345               reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);
2346               reader_array_start_pos = subreader.u.array.start_pos;
2347             }
2348           else
2349             {
2350               /* quiet gcc */
2351               reader_array_len_pos = -1;
2352               reader_array_start_pos = -1;
2353             }
2354
2355           _dbus_type_reader_get_signature (&subreader, &sig_str,
2356                                            &sig_start, &sig_len);
2357
2358 #if RECURSIVE_MARSHAL_WRITE_TRACE
2359           _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n",
2360                          _dbus_type_to_string (current_type),
2361                          reader->value_pos,
2362                          subreader.value_pos,
2363                          writer->value_pos,
2364                          start_after ? start_after->value_pos : -1,
2365                          _dbus_string_get_length (writer->value_str),
2366                          inside_start_after, this_is_start_after);
2367 #endif
2368
2369           if (!inside_start_after && !this_is_start_after)
2370             enable_if_after (writer, &subreader, start_after);
2371           enabled_at_recurse = writer->enabled;
2372           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
2373                                                         sig_str, sig_start, sig_len,
2374                                                         &subwriter, FALSE))
2375             goto oom;
2376
2377 #if RECURSIVE_MARSHAL_WRITE_TRACE
2378           _dbus_verbose ("recursed into subwriter at %d write target len %d\n",
2379                          subwriter.value_pos,
2380                          _dbus_string_get_length (subwriter.value_str));
2381 #endif
2382
2383           if (!writer_write_reader_helper (&subwriter, &subreader, start_after,
2384                                            start_after_new_pos, start_after_new_len,
2385                                            fixups,
2386                                            inside_start_after ||
2387                                            this_is_start_after))
2388             goto oom;
2389
2390 #if RECURSIVE_MARSHAL_WRITE_TRACE
2391           _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d  write target len %d\n",
2392                          _dbus_type_to_string (current_type),
2393                          subreader.value_pos,
2394                          writer->value_pos,
2395                          subwriter.value_pos,
2396                          _dbus_string_get_length (writer->value_str));
2397 #endif
2398
2399           if (!inside_start_after && !this_is_start_after)
2400             enable_if_after (writer, &subreader, start_after);
2401           past_start_after = writer->enabled;
2402           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
2403             goto oom;
2404
2405           /* If we weren't enabled when we recursed, we didn't
2406            * write an array len; if we passed start_after
2407            * somewhere inside the array, then we need to generate
2408            * a fixup.
2409            */
2410           if (start_after != NULL &&
2411               !enabled_at_recurse && past_start_after &&
2412               current_type == DBUS_TYPE_ARRAY &&
2413               fixups != NULL)
2414             {
2415               DBusArrayLenFixup fixup;
2416               int bytes_written_after_start_after;
2417               int bytes_before_start_after;
2418               int old_len;
2419
2420               /* this subwriter access is moderately unkosher since we
2421                * already unrecursed, but it works as long as unrecurse
2422                * doesn't break us on purpose
2423                */
2424               bytes_written_after_start_after = writer_get_array_len (&subwriter);
2425
2426               bytes_before_start_after =
2427                 start_after->value_pos - reader_array_start_pos;
2428
2429               fixup.len_pos_in_reader = reader_array_len_pos;
2430               fixup.new_len =
2431                 bytes_before_start_after +
2432                 start_after_new_len +
2433                 bytes_written_after_start_after;
2434
2435               old_len = _dbus_marshal_read_uint32 (reader->value_str,
2436                                                    fixup.len_pos_in_reader,
2437                                                    reader->byte_order, NULL);
2438
2439               if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))
2440                 goto oom;
2441
2442 #if RECURSIVE_MARSHAL_WRITE_TRACE
2443               _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n",
2444                              fixup.len_pos_in_reader,
2445                              fixup.new_len,
2446                              reader_array_start_pos,
2447                              start_after->value_pos,
2448                              bytes_before_start_after,
2449                              start_after_new_len,
2450                              bytes_written_after_start_after);
2451 #endif
2452             }
2453         }
2454       else
2455         {
2456           DBusBasicValue val;
2457
2458           _dbus_assert (_dbus_type_is_basic (current_type));
2459
2460 #if RECURSIVE_MARSHAL_WRITE_TRACE
2461           _dbus_verbose ("Reading basic value %s at %d\n",
2462                          _dbus_type_to_string (current_type),
2463                          reader->value_pos);
2464 #endif
2465
2466           _dbus_type_reader_read_basic (reader, &val);
2467
2468 #if RECURSIVE_MARSHAL_WRITE_TRACE
2469           _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",
2470                          _dbus_type_to_string (current_type),
2471                          writer->value_pos,
2472                          _dbus_string_get_length (writer->value_str),
2473                          inside_start_after);
2474 #endif
2475           if (!inside_start_after)
2476             enable_if_after (writer, reader, start_after);
2477           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
2478             goto oom;
2479 #if RECURSIVE_MARSHAL_WRITE_TRACE
2480           _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",
2481                          _dbus_type_to_string (current_type),
2482                          writer->value_pos,
2483                          _dbus_string_get_length (writer->value_str));
2484 #endif
2485         }
2486
2487       _dbus_type_reader_next (reader);
2488     }
2489
2490   return TRUE;
2491
2492  oom:
2493   if (fixups)
2494     apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */
2495
2496   return FALSE;
2497 }
2498
2499 /**
2500  * Iterate through all values in the given reader, writing a copy of
2501  * each value to the writer.  The reader will be moved forward to its
2502  * end position.
2503  *
2504  * If a reader start_after is provided, it should be a reader for the
2505  * same data as the reader to be written. Only values occurring after
2506  * the value pointed to by start_after will be written to the writer.
2507  *
2508  * If start_after is provided, then the copy of the reader will be
2509  * partial. This means that array lengths will not have been copied.
2510  * The assumption is that you wrote a new version of the value at
2511  * start_after to the writer. You have to pass in the start position
2512  * and length of the new value. (If you are deleting the value
2513  * at start_after, pass in 0 for the length.)
2514  *
2515  * If the fixups parameter is non-#NULL, then any array length that
2516  * was read but not written due to start_after will be provided
2517  * as a #DBusArrayLenFixup. The fixup contains the position of the
2518  * array length in the source data, and the correct array length
2519  * assuming you combine the source data before start_after with
2520  * the written data at start_after and beyond.
2521  *
2522  * @param writer the writer to copy to
2523  * @param reader the reader to copy from
2524  * @param start_after #NULL or a reader showing where to start
2525  * @param start_after_new_pos the position of start_after equivalent in the target data
2526  * @param start_after_new_len the length of start_after equivalent in the target data
2527  * @param fixups list to append #DBusArrayLenFixup if the write was partial
2528  * @returns #FALSE if no memory
2529  */
2530 dbus_bool_t
2531 _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,
2532                                         DBusTypeReader       *reader,
2533                                         const DBusTypeReader *start_after,
2534                                         int                   start_after_new_pos,
2535                                         int                   start_after_new_len,
2536                                         DBusList            **fixups)
2537 {
2538   DBusTypeWriter orig;
2539   int orig_type_len;
2540   int orig_value_len;
2541   int new_bytes;
2542   int orig_enabled;
2543
2544   orig = *writer;
2545   orig_type_len = _dbus_string_get_length (writer->type_str);
2546   orig_value_len = _dbus_string_get_length (writer->value_str);
2547   orig_enabled = writer->enabled;
2548
2549   if (start_after)
2550     _dbus_type_writer_set_enabled (writer, FALSE);
2551
2552   if (!writer_write_reader_helper (writer, reader, start_after,
2553                                    start_after_new_pos,
2554                                    start_after_new_len,
2555                                    fixups, FALSE))
2556     goto oom;
2557
2558   _dbus_type_writer_set_enabled (writer, orig_enabled);
2559   return TRUE;
2560
2561  oom:
2562   if (!writer->type_pos_is_expectation)
2563     {
2564       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
2565       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
2566     }
2567   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
2568   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
2569
2570   *writer = orig;
2571
2572   return FALSE;
2573 }
2574
2575 /**
2576  * Iterate through all values in the given reader, writing a copy of
2577  * each value to the writer.  The reader will be moved forward to its
2578  * end position.
2579  *
2580  * @param writer the writer to copy to
2581  * @param reader the reader to copy from
2582  * @returns #FALSE if no memory
2583  */
2584 dbus_bool_t
2585 _dbus_type_writer_write_reader (DBusTypeWriter       *writer,
2586                                 DBusTypeReader       *reader)
2587 {
2588   return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
2589 }
2590
2591 /**
2592  * If disabled, a writer can still be iterated forward and recursed/unrecursed
2593  * but won't write any values. Types will still be written unless the
2594  * writer is a "values only" writer, because the writer needs access to
2595  * a valid signature to be able to iterate.
2596  *
2597  * @param writer the type writer
2598  * @param enabled #TRUE if values should be written
2599  */
2600 void
2601 _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,
2602                                dbus_bool_t       enabled)
2603 {
2604   writer->enabled = enabled != FALSE;
2605 }
2606
2607 /** @} */ /* end of DBusMarshal group */
2608
2609 #ifdef DBUS_BUILD_TESTS
2610 #include "dbus-test.h"
2611 #include "dbus-list.h"
2612 #include <stdio.h>
2613 #include <stdlib.h>
2614
2615 /* Whether to do the OOM stuff (only with other expensive tests) */
2616 #define TEST_OOM_HANDLING 0
2617 /* We do start offset 0 through 9, to get various alignment cases. Still this
2618  * obviously makes the test suite run 10x as slow.
2619  */
2620 #define MAX_INITIAL_OFFSET 9
2621
2622 /* Largest iteration count to test copying, realignment,
2623  * etc. with. i.e. we only test this stuff with some of the smaller
2624  * data sets.
2625  */
2626 #define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000
2627
2628 typedef struct
2629 {
2630   int byte_order;
2631   int initial_offset;
2632   DBusString signature;
2633   DBusString body;
2634 } DataBlock;
2635
2636 typedef struct
2637 {
2638   int saved_sig_len;
2639   int saved_body_len;
2640 } DataBlockState;
2641
2642 #define N_FENCE_BYTES 5
2643 #define FENCE_BYTES_STR "abcde"
2644 #define INITIAL_PADDING_BYTE '\0'
2645
2646 static dbus_bool_t
2647 data_block_init (DataBlock *block,
2648                  int        byte_order,
2649                  int        initial_offset)
2650 {
2651   if (!_dbus_string_init (&block->signature))
2652     return FALSE;
2653
2654   if (!_dbus_string_init (&block->body))
2655     {
2656       _dbus_string_free (&block->signature);
2657       return FALSE;
2658     }
2659
2660   if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
2661                                   INITIAL_PADDING_BYTE) ||
2662       !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
2663                                   INITIAL_PADDING_BYTE) ||
2664       !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
2665       !_dbus_string_append (&block->body, FENCE_BYTES_STR))
2666     {
2667       _dbus_string_free (&block->signature);
2668       _dbus_string_free (&block->body);
2669       return FALSE;
2670     }
2671
2672   block->byte_order = byte_order;
2673   block->initial_offset = initial_offset;
2674
2675   return TRUE;
2676 }
2677
2678 static void
2679 data_block_save (DataBlock      *block,
2680                  DataBlockState *state)
2681 {
2682   state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
2683   state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
2684 }
2685
2686 static void
2687 data_block_restore (DataBlock      *block,
2688                     DataBlockState *state)
2689 {
2690   _dbus_string_delete (&block->signature,
2691                        state->saved_sig_len,
2692                        _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
2693   _dbus_string_delete (&block->body,
2694                        state->saved_body_len,
2695                        _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
2696 }
2697
2698 static void
2699 data_block_verify (DataBlock *block)
2700 {
2701   if (!_dbus_string_ends_with_c_str (&block->signature,
2702                                      FENCE_BYTES_STR))
2703     {
2704       int offset;
2705
2706       offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
2707       if (offset < 0)
2708         offset = 0;
2709
2710       _dbus_verbose_bytes_of_string (&block->signature,
2711                                      offset,
2712                                      _dbus_string_get_length (&block->signature) - offset);
2713       _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
2714     }
2715   if (!_dbus_string_ends_with_c_str (&block->body,
2716                                      FENCE_BYTES_STR))
2717     {
2718       int offset;
2719
2720       offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
2721       if (offset < 0)
2722         offset = 0;
2723
2724       _dbus_verbose_bytes_of_string (&block->body,
2725                                      offset,
2726                                      _dbus_string_get_length (&block->body) - offset);
2727       _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
2728     }
2729
2730   _dbus_assert (_dbus_string_validate_nul (&block->signature,
2731                                            0, block->initial_offset));
2732   _dbus_assert (_dbus_string_validate_nul (&block->body,
2733                                            0, block->initial_offset));
2734 }
2735
2736 static void
2737 data_block_free (DataBlock *block)
2738 {
2739   data_block_verify (block);
2740
2741   _dbus_string_free (&block->signature);
2742   _dbus_string_free (&block->body);
2743 }
2744
2745 static void
2746 data_block_reset (DataBlock *block)
2747 {
2748   data_block_verify (block);
2749
2750   _dbus_string_delete (&block->signature,
2751                        block->initial_offset,
2752                        _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
2753   _dbus_string_delete (&block->body,
2754                        block->initial_offset,
2755                        _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
2756
2757   data_block_verify (block);
2758 }
2759
2760 static void
2761 data_block_init_reader_writer (DataBlock      *block,
2762                                DBusTypeReader *reader,
2763                                DBusTypeWriter *writer)
2764 {
2765   if (reader)
2766     _dbus_type_reader_init (reader,
2767                             block->byte_order,
2768                             &block->signature,
2769                             block->initial_offset,
2770                             &block->body,
2771                             block->initial_offset);
2772
2773   if (writer)
2774     _dbus_type_writer_init (writer,
2775                             block->byte_order,
2776                             &block->signature,
2777                             _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
2778                             &block->body,
2779                             _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
2780 }
2781
2782 static void
2783 real_check_expected_type (DBusTypeReader *reader,
2784                           int             expected,
2785                           const char     *funcname,
2786                           int             line)
2787 {
2788   int t;
2789
2790   t = _dbus_type_reader_get_current_type (reader);
2791
2792   if (t != expected)
2793     {
2794       _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
2795                   _dbus_type_to_string (t),
2796                   _dbus_type_to_string (expected),
2797                   funcname, line);
2798
2799       _dbus_assert_not_reached ("read wrong type");
2800     }
2801 }
2802
2803 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
2804
2805 #define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \
2806  {                                                                                      \
2807     _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \
2808                               _DBUS_FUNCTION_NAME, __LINE__);                           \
2809     _dbus_assert_not_reached ("test failed");                                           \
2810  }                                                                                      \
2811 } while (0)
2812
2813 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \
2814  {                                                                                      \
2815     _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \
2816                               _DBUS_FUNCTION_NAME, __LINE__);                           \
2817     _dbus_assert_not_reached ("test failed");                                           \
2818  }                                                                                      \
2819  check_expected_type (reader, DBUS_TYPE_INVALID);                                       \
2820 } while (0)
2821
2822 typedef struct TestTypeNode               TestTypeNode;
2823 typedef struct TestTypeNodeClass          TestTypeNodeClass;
2824 typedef struct TestTypeNodeContainer      TestTypeNodeContainer;
2825 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
2826
2827 struct TestTypeNode
2828 {
2829   const TestTypeNodeClass *klass;
2830 };
2831
2832 struct TestTypeNodeContainer
2833 {
2834   TestTypeNode base;
2835   DBusList    *children;
2836 };
2837
2838 struct TestTypeNodeClass
2839 {
2840   int typecode;
2841
2842   int instance_size;
2843
2844   int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
2845
2846   dbus_bool_t   (* construct)     (TestTypeNode   *node);
2847   void          (* destroy)       (TestTypeNode   *node);
2848
2849   dbus_bool_t (* write_value)     (TestTypeNode   *node,
2850                                    DataBlock      *block,
2851                                    DBusTypeWriter *writer,
2852                                    int             seed);
2853   dbus_bool_t (* read_value)      (TestTypeNode   *node,
2854                                    DBusTypeReader *reader,
2855                                    int             seed);
2856   dbus_bool_t (* set_value)       (TestTypeNode   *node,
2857                                    DBusTypeReader *reader,
2858                                    DBusTypeReader *realign_root,
2859                                    int             seed);
2860   dbus_bool_t (* build_signature) (TestTypeNode   *node,
2861                                    DBusString     *str);
2862   dbus_bool_t (* write_multi)     (TestTypeNode   *node,
2863                                    DataBlock      *block,
2864                                    DBusTypeWriter *writer,
2865                                    int             seed,
2866                                    int             count);
2867   dbus_bool_t (* read_multi)      (TestTypeNode   *node,
2868                                    DBusTypeReader *reader,
2869                                    int             seed,
2870                                    int             count);
2871 };
2872
2873 struct TestTypeNodeContainerClass
2874 {
2875   TestTypeNodeClass base;
2876 };
2877
2878 /* FIXME this could be chilled out substantially by unifying
2879  * the basic types into basic_write_value/basic_read_value
2880  * and by merging read_value and set_value into one function
2881  * taking a flag argument.
2882  */
2883 static dbus_bool_t int32_write_value       (TestTypeNode   *node,
2884                                             DataBlock      *block,
2885                                             DBusTypeWriter *writer,
2886                                             int             seed);
2887 static dbus_bool_t int32_read_value        (TestTypeNode   *node,
2888                                             DBusTypeReader *reader,
2889                                             int             seed);
2890 static dbus_bool_t int32_set_value         (TestTypeNode   *node,
2891                                             DBusTypeReader *reader,
2892                                             DBusTypeReader *realign_root,
2893                                             int             seed);
2894 static dbus_bool_t int32_write_multi       (TestTypeNode   *node,
2895                                             DataBlock      *block,
2896                                             DBusTypeWriter *writer,
2897                                             int             seed,
2898                                             int             count);
2899 static dbus_bool_t int32_read_multi        (TestTypeNode   *node,
2900                                             DBusTypeReader *reader,
2901                                             int             seed,
2902                                             int             count);
2903 static dbus_bool_t int64_write_value       (TestTypeNode   *node,
2904                                             DataBlock      *block,
2905                                             DBusTypeWriter *writer,
2906                                             int             seed);
2907 static dbus_bool_t int64_read_value        (TestTypeNode   *node,
2908                                             DBusTypeReader *reader,
2909                                             int             seed);
2910 static dbus_bool_t int64_set_value         (TestTypeNode   *node,
2911                                             DBusTypeReader *reader,
2912                                             DBusTypeReader *realign_root,
2913                                             int             seed);
2914 static dbus_bool_t string_write_value      (TestTypeNode   *node,
2915                                             DataBlock      *block,
2916                                             DBusTypeWriter *writer,
2917                                             int             seed);
2918 static dbus_bool_t string_read_value       (TestTypeNode   *node,
2919                                             DBusTypeReader *reader,
2920                                             int             seed);
2921 static dbus_bool_t string_set_value        (TestTypeNode   *node,
2922                                             DBusTypeReader *reader,
2923                                             DBusTypeReader *realign_root,
2924                                             int             seed);
2925 static dbus_bool_t bool_write_value        (TestTypeNode   *node,
2926                                             DataBlock      *block,
2927                                             DBusTypeWriter *writer,
2928                                             int             seed);
2929 static dbus_bool_t bool_read_value         (TestTypeNode   *node,
2930                                             DBusTypeReader *reader,
2931                                             int             seed);
2932 static dbus_bool_t bool_set_value          (TestTypeNode   *node,
2933                                             DBusTypeReader *reader,
2934                                             DBusTypeReader *realign_root,
2935                                             int             seed);
2936 static dbus_bool_t byte_write_value        (TestTypeNode   *node,
2937                                             DataBlock      *block,
2938                                             DBusTypeWriter *writer,
2939                                             int             seed);
2940 static dbus_bool_t byte_read_value         (TestTypeNode   *node,
2941                                             DBusTypeReader *reader,
2942                                             int             seed);
2943 static dbus_bool_t byte_set_value          (TestTypeNode   *node,
2944                                             DBusTypeReader *reader,
2945                                             DBusTypeReader *realign_root,
2946                                             int             seed);
2947 static dbus_bool_t double_write_value      (TestTypeNode   *node,
2948                                             DataBlock      *block,
2949                                             DBusTypeWriter *writer,
2950                                             int             seed);
2951 static dbus_bool_t double_read_value       (TestTypeNode   *node,
2952                                             DBusTypeReader *reader,
2953                                             int             seed);
2954 static dbus_bool_t double_set_value        (TestTypeNode   *node,
2955                                             DBusTypeReader *reader,
2956                                             DBusTypeReader *realign_root,
2957                                             int             seed);
2958 static dbus_bool_t object_path_write_value (TestTypeNode   *node,
2959                                             DataBlock      *block,
2960                                             DBusTypeWriter *writer,
2961                                             int             seed);
2962 static dbus_bool_t object_path_read_value  (TestTypeNode   *node,
2963                                             DBusTypeReader *reader,
2964                                             int             seed);
2965 static dbus_bool_t object_path_set_value   (TestTypeNode   *node,
2966                                             DBusTypeReader *reader,
2967                                             DBusTypeReader *realign_root,
2968                                             int             seed);
2969 static dbus_bool_t signature_write_value   (TestTypeNode   *node,
2970                                             DataBlock      *block,
2971                                             DBusTypeWriter *writer,
2972                                             int             seed);
2973 static dbus_bool_t signature_read_value    (TestTypeNode   *node,
2974                                             DBusTypeReader *reader,
2975                                             int             seed);
2976 static dbus_bool_t signature_set_value     (TestTypeNode   *node,
2977                                             DBusTypeReader *reader,
2978                                             DBusTypeReader *realign_root,
2979                                             int             seed);
2980 static dbus_bool_t struct_write_value      (TestTypeNode   *node,
2981                                             DataBlock      *block,
2982                                             DBusTypeWriter *writer,
2983                                             int             seed);
2984 static dbus_bool_t struct_read_value       (TestTypeNode   *node,
2985                                             DBusTypeReader *reader,
2986                                             int             seed);
2987 static dbus_bool_t struct_set_value        (TestTypeNode   *node,
2988                                             DBusTypeReader *reader,
2989                                             DBusTypeReader *realign_root,
2990                                             int             seed);
2991 static dbus_bool_t struct_build_signature  (TestTypeNode   *node,
2992                                             DBusString     *str);
2993 static dbus_bool_t array_write_value       (TestTypeNode   *node,
2994                                             DataBlock      *block,
2995                                             DBusTypeWriter *writer,
2996                                             int             seed);
2997 static dbus_bool_t array_read_value        (TestTypeNode   *node,
2998                                             DBusTypeReader *reader,
2999                                             int             seed);
3000 static dbus_bool_t array_set_value         (TestTypeNode   *node,
3001                                             DBusTypeReader *reader,
3002                                             DBusTypeReader *realign_root,
3003                                             int             seed);
3004 static dbus_bool_t array_build_signature   (TestTypeNode   *node,
3005                                             DBusString     *str);
3006 static dbus_bool_t variant_write_value     (TestTypeNode   *node,
3007                                             DataBlock      *block,
3008                                             DBusTypeWriter *writer,
3009                                             int             seed);
3010 static dbus_bool_t variant_read_value      (TestTypeNode   *node,
3011                                             DBusTypeReader *reader,
3012                                             int             seed);
3013 static dbus_bool_t variant_set_value       (TestTypeNode   *node,
3014                                             DBusTypeReader *reader,
3015                                             DBusTypeReader *realign_root,
3016                                             int             seed);
3017 static void        container_destroy       (TestTypeNode   *node);
3018
3019
3020 static const TestTypeNodeClass int32_class = {
3021   DBUS_TYPE_INT32,
3022   sizeof (TestTypeNode),
3023   0,
3024   NULL,
3025   NULL,
3026   int32_write_value,
3027   int32_read_value,
3028   int32_set_value,
3029   NULL,
3030   int32_write_multi,
3031   int32_read_multi
3032 };
3033
3034 static const TestTypeNodeClass uint32_class = {
3035   DBUS_TYPE_UINT32,
3036   sizeof (TestTypeNode),
3037   0,
3038   NULL,
3039   NULL,
3040   int32_write_value, /* recycle from int32 */
3041   int32_read_value,  /* recycle from int32 */
3042   int32_set_value,   /* recycle from int32 */
3043   NULL,
3044   int32_write_multi, /* recycle from int32 */
3045   int32_read_multi   /* recycle from int32 */
3046 };
3047
3048 static const TestTypeNodeClass int64_class = {
3049   DBUS_TYPE_INT64,
3050   sizeof (TestTypeNode),
3051   0,
3052   NULL,
3053   NULL,
3054   int64_write_value,
3055   int64_read_value,
3056   int64_set_value,
3057   NULL,
3058   NULL, /* FIXME */
3059   NULL  /* FIXME */
3060 };
3061
3062 static const TestTypeNodeClass uint64_class = {
3063   DBUS_TYPE_UINT64,
3064   sizeof (TestTypeNode),
3065   0,
3066   NULL,
3067   NULL,
3068   int64_write_value, /* recycle from int64 */
3069   int64_read_value,  /* recycle from int64 */
3070   int64_set_value,   /* recycle from int64 */
3071   NULL,
3072   NULL, /* FIXME */
3073   NULL  /* FIXME */
3074 };
3075
3076 static const TestTypeNodeClass string_0_class = {
3077   DBUS_TYPE_STRING,
3078   sizeof (TestTypeNode),
3079   0, /* string length */
3080   NULL,
3081   NULL,
3082   string_write_value,
3083   string_read_value,
3084   string_set_value,
3085   NULL,
3086   NULL,
3087   NULL
3088 };
3089
3090 static const TestTypeNodeClass string_1_class = {
3091   DBUS_TYPE_STRING,
3092   sizeof (TestTypeNode),
3093   1, /* string length */
3094   NULL,
3095   NULL,
3096   string_write_value,
3097   string_read_value,
3098   string_set_value,
3099   NULL,
3100   NULL,
3101   NULL
3102 };
3103
3104 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
3105 static const TestTypeNodeClass string_3_class = {
3106   DBUS_TYPE_STRING,
3107   sizeof (TestTypeNode),
3108   3, /* string length */
3109   NULL,
3110   NULL,
3111   string_write_value,
3112   string_read_value,
3113   string_set_value,
3114   NULL,
3115   NULL,
3116   NULL
3117 };
3118
3119 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
3120 static const TestTypeNodeClass string_8_class = {
3121   DBUS_TYPE_STRING,
3122   sizeof (TestTypeNode),
3123   8, /* string length */
3124   NULL,
3125   NULL,
3126   string_write_value,
3127   string_read_value,
3128   string_set_value,
3129   NULL,
3130   NULL,
3131   NULL
3132 };
3133
3134 static const TestTypeNodeClass bool_class = {
3135   DBUS_TYPE_BOOLEAN,
3136   sizeof (TestTypeNode),
3137   0,
3138   NULL,
3139   NULL,
3140   bool_write_value,
3141   bool_read_value,
3142   bool_set_value,
3143   NULL,
3144   NULL, /* FIXME */
3145   NULL  /* FIXME */
3146 };
3147
3148 static const TestTypeNodeClass byte_class = {
3149   DBUS_TYPE_BYTE,
3150   sizeof (TestTypeNode),
3151   0,
3152   NULL,
3153   NULL,
3154   byte_write_value,
3155   byte_read_value,
3156   byte_set_value,
3157   NULL,
3158   NULL, /* FIXME */
3159   NULL  /* FIXME */
3160 };
3161
3162 static const TestTypeNodeClass double_class = {
3163   DBUS_TYPE_DOUBLE,
3164   sizeof (TestTypeNode),
3165   0,
3166   NULL,
3167   NULL,
3168   double_write_value,
3169   double_read_value,
3170   double_set_value,
3171   NULL,
3172   NULL, /* FIXME */
3173   NULL  /* FIXME */
3174 };
3175
3176 static const TestTypeNodeClass object_path_class = {
3177   DBUS_TYPE_OBJECT_PATH,
3178   sizeof (TestTypeNode),
3179   0,
3180   NULL,
3181   NULL,
3182   object_path_write_value,
3183   object_path_read_value,
3184   object_path_set_value,
3185   NULL,
3186   NULL,
3187   NULL
3188 };
3189
3190 static const TestTypeNodeClass signature_class = {
3191   DBUS_TYPE_SIGNATURE,
3192   sizeof (TestTypeNode),
3193   0,
3194   NULL,
3195   NULL,
3196   signature_write_value,
3197   signature_read_value,
3198   signature_set_value,
3199   NULL,
3200   NULL,
3201   NULL
3202 };
3203
3204 static const TestTypeNodeClass struct_1_class = {
3205   DBUS_TYPE_STRUCT,
3206   sizeof (TestTypeNodeContainer),
3207   1, /* number of times children appear as fields */
3208   NULL,
3209   container_destroy,
3210   struct_write_value,
3211   struct_read_value,
3212   struct_set_value,
3213   struct_build_signature,
3214   NULL,
3215   NULL
3216 };
3217
3218 static const TestTypeNodeClass struct_2_class = {
3219   DBUS_TYPE_STRUCT,
3220   sizeof (TestTypeNodeContainer),
3221   2, /* number of times children appear as fields */
3222   NULL,
3223   container_destroy,
3224   struct_write_value,
3225   struct_read_value,
3226   struct_set_value,
3227   struct_build_signature,
3228   NULL,
3229   NULL
3230 };
3231
3232 static dbus_bool_t arrays_write_fixed_in_blocks = FALSE;
3233
3234 static const TestTypeNodeClass array_0_class = {
3235   DBUS_TYPE_ARRAY,
3236   sizeof (TestTypeNodeContainer),
3237   0, /* number of array elements */
3238   NULL,
3239   container_destroy,
3240   array_write_value,
3241   array_read_value,
3242   array_set_value,
3243   array_build_signature,
3244   NULL,
3245   NULL
3246 };
3247
3248 static const TestTypeNodeClass array_1_class = {
3249   DBUS_TYPE_ARRAY,
3250   sizeof (TestTypeNodeContainer),
3251   1, /* number of array elements */
3252   NULL,
3253   container_destroy,
3254   array_write_value,
3255   array_read_value,
3256   array_set_value,
3257   array_build_signature,
3258   NULL,
3259   NULL
3260 };
3261
3262 static const TestTypeNodeClass array_2_class = {
3263   DBUS_TYPE_ARRAY,
3264   sizeof (TestTypeNodeContainer),
3265   2, /* number of array elements */
3266   NULL,
3267   container_destroy,
3268   array_write_value,
3269   array_read_value,
3270   array_set_value,
3271   array_build_signature,
3272   NULL,
3273   NULL
3274 };
3275
3276 static const TestTypeNodeClass array_9_class = {
3277   DBUS_TYPE_ARRAY,
3278   sizeof (TestTypeNodeContainer),
3279   9, /* number of array elements */
3280   NULL,
3281   container_destroy,
3282   array_write_value,
3283   array_read_value,
3284   array_set_value,
3285   array_build_signature,
3286   NULL,
3287   NULL
3288 };
3289
3290 static const TestTypeNodeClass variant_class = {
3291   DBUS_TYPE_VARIANT,
3292   sizeof (TestTypeNodeContainer),
3293   0,
3294   NULL,
3295   container_destroy,
3296   variant_write_value,
3297   variant_read_value,
3298   variant_set_value,
3299   NULL,
3300   NULL,
3301   NULL
3302 };
3303
3304 static const TestTypeNodeClass* const
3305 basic_nodes[] = {
3306   &int32_class,
3307   &uint32_class,
3308   &int64_class,
3309   &uint64_class,
3310   &bool_class,
3311   &byte_class,
3312   &double_class,
3313   &string_0_class,
3314   &string_1_class,
3315   &string_3_class,
3316   &string_8_class,
3317   &object_path_class,
3318   &signature_class
3319 };
3320 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
3321
3322 static const TestTypeNodeClass* const
3323 container_nodes[] = {
3324   &struct_1_class,
3325   &array_1_class,
3326   &struct_2_class,
3327   &array_0_class,
3328   &array_2_class,
3329   &variant_class
3330   /* array_9_class is omitted on purpose, it's too slow;
3331    * we only use it in one hardcoded test below
3332    */
3333 };
3334 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
3335
3336 static TestTypeNode*
3337 node_new (const TestTypeNodeClass *klass)
3338 {
3339   TestTypeNode *node;
3340
3341   node = dbus_malloc0 (klass->instance_size);
3342   if (node == NULL)
3343     return NULL;
3344
3345   node->klass = klass;
3346
3347   if (klass->construct)
3348     {
3349       if (!(* klass->construct) (node))
3350         {
3351           dbus_free (node);
3352           return FALSE;
3353         }
3354     }
3355
3356   return node;
3357 }
3358
3359 static void
3360 node_destroy (TestTypeNode *node)
3361 {
3362   if (node->klass->destroy)
3363     (* node->klass->destroy) (node);
3364   dbus_free (node);
3365 }
3366
3367 static dbus_bool_t
3368 node_write_value (TestTypeNode   *node,
3369                   DataBlock      *block,
3370                   DBusTypeWriter *writer,
3371                   int             seed)
3372 {
3373   dbus_bool_t retval;
3374
3375   retval = (* node->klass->write_value) (node, block, writer, seed);
3376
3377 #if 0
3378   /* Handy to see where things break, but too expensive to do all the time */
3379   data_block_verify (block);
3380 #endif
3381
3382   return retval;
3383 }
3384
3385 static dbus_bool_t
3386 node_read_value (TestTypeNode   *node,
3387                  DBusTypeReader *reader,
3388                  int             seed)
3389 {
3390   DBusTypeMark mark;
3391   DBusTypeReader restored;
3392
3393   _dbus_type_reader_save_mark (reader, &mark);
3394
3395   if (!(* node->klass->read_value) (node, reader, seed))
3396     return FALSE;
3397
3398   _dbus_type_reader_init_from_mark (&restored,
3399                                     reader->byte_order,
3400                                     reader->type_str,
3401                                     reader->value_str,
3402                                     &mark);
3403
3404   if (!(* node->klass->read_value) (node, &restored, seed))
3405     return FALSE;
3406
3407   return TRUE;
3408 }
3409
3410 /* Warning: if this one fails due to OOM, it has side effects (can
3411  * modify only some of the sub-values). OK in a test suite, but we
3412  * never do this in real code.
3413  */
3414 static dbus_bool_t
3415 node_set_value (TestTypeNode   *node,
3416                 DBusTypeReader *reader,
3417                 DBusTypeReader *realign_root,
3418                 int             seed)
3419 {
3420   if (!(* node->klass->set_value) (node, reader, realign_root, seed))
3421     return FALSE;
3422
3423   return TRUE;
3424 }
3425
3426 static dbus_bool_t
3427 node_build_signature (TestTypeNode *node,
3428                       DBusString   *str)
3429 {
3430   if (node->klass->build_signature)
3431     return (* node->klass->build_signature) (node, str);
3432   else
3433     return _dbus_string_append_byte (str, node->klass->typecode);
3434 }
3435
3436 static dbus_bool_t
3437 node_append_child (TestTypeNode *node,
3438                    TestTypeNode *child)
3439 {
3440   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3441
3442   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
3443
3444   if (!_dbus_list_append (&container->children, child))
3445     _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 */
3446
3447   return TRUE;
3448 }
3449
3450 static dbus_bool_t
3451 node_write_multi (TestTypeNode   *node,
3452                   DataBlock      *block,
3453                   DBusTypeWriter *writer,
3454                   int             seed,
3455                   int             n_copies)
3456 {
3457   dbus_bool_t retval;
3458
3459   _dbus_assert (node->klass->write_multi != NULL);
3460   retval = (* node->klass->write_multi) (node, block, writer, seed, n_copies);
3461
3462 #if 0
3463   /* Handy to see where things break, but too expensive to do all the time */
3464   data_block_verify (block);
3465 #endif
3466
3467   return retval;
3468 }
3469
3470 static dbus_bool_t
3471 node_read_multi (TestTypeNode   *node,
3472                  DBusTypeReader *reader,
3473                  int             seed,
3474                  int             n_copies)
3475 {
3476   _dbus_assert (node->klass->read_multi != NULL);
3477
3478   if (!(* node->klass->read_multi) (node, reader, seed, n_copies))
3479     return FALSE;
3480
3481   return TRUE;
3482 }
3483
3484 static int n_iterations_completed_total = 0;
3485 static int n_iterations_completed_this_test = 0;
3486 static int n_iterations_expected_this_test = 0;
3487
3488 typedef struct
3489 {
3490   const DBusString   *signature;
3491   DataBlock          *block;
3492   int                 type_offset;
3493   TestTypeNode      **nodes;
3494   int                 n_nodes;
3495 } NodeIterationData;
3496
3497
3498 static dbus_bool_t
3499 run_test_copy (NodeIterationData *nid)
3500 {
3501   DataBlock *src;
3502   DataBlock dest;
3503   dbus_bool_t retval;
3504   DBusTypeReader reader;
3505   DBusTypeWriter writer;
3506
3507   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
3508
3509   src = nid->block;
3510
3511   retval = FALSE;
3512
3513   if (!data_block_init (&dest, src->byte_order, src->initial_offset))
3514     return FALSE;
3515
3516   data_block_init_reader_writer (src, &reader, NULL);
3517   data_block_init_reader_writer (&dest, NULL, &writer);
3518
3519   /* DBusTypeWriter assumes it's writing into an existing signature,
3520    * so doesn't add nul on its own. We have to do that.
3521    */
3522   if (!_dbus_string_insert_byte (&dest.signature,
3523                                  dest.initial_offset, '\0'))
3524     goto out;
3525
3526   if (!_dbus_type_writer_write_reader (&writer, &reader))
3527     goto out;
3528
3529   /* Data blocks should now be identical */
3530   if (!_dbus_string_equal (&src->signature, &dest.signature))
3531     {
3532       _dbus_verbose ("SOURCE\n");
3533       _dbus_verbose_bytes_of_string (&src->signature, 0,
3534                                      _dbus_string_get_length (&src->signature));
3535       _dbus_verbose ("DEST\n");
3536       _dbus_verbose_bytes_of_string (&dest.signature, 0,
3537                                      _dbus_string_get_length (&dest.signature));
3538       _dbus_assert_not_reached ("signatures did not match");
3539     }
3540
3541   if (!_dbus_string_equal (&src->body, &dest.body))
3542     {
3543       _dbus_verbose ("SOURCE\n");
3544       _dbus_verbose_bytes_of_string (&src->body, 0,
3545                                      _dbus_string_get_length (&src->body));
3546       _dbus_verbose ("DEST\n");
3547       _dbus_verbose_bytes_of_string (&dest.body, 0,
3548                                      _dbus_string_get_length (&dest.body));
3549       _dbus_assert_not_reached ("bodies did not match");
3550     }
3551
3552   retval = TRUE;
3553
3554  out:
3555
3556   data_block_free (&dest);
3557
3558   return retval;
3559 }
3560
3561 static dbus_bool_t
3562 run_test_values_only_write (NodeIterationData *nid)
3563 {
3564   DBusTypeReader reader;
3565   DBusTypeWriter writer;
3566   int i;
3567   dbus_bool_t retval;
3568   int sig_len;
3569
3570   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
3571
3572   retval = FALSE;
3573
3574   data_block_reset (nid->block);
3575
3576   sig_len = _dbus_string_get_length (nid->signature);
3577
3578   _dbus_type_writer_init_values_only (&writer,
3579                                       nid->block->byte_order,
3580                                       nid->signature, 0,
3581                                       &nid->block->body,
3582                                       _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES);
3583   _dbus_type_reader_init (&reader,
3584                           nid->block->byte_order,
3585                           nid->signature, 0,
3586                           &nid->block->body,
3587                           nid->block->initial_offset);
3588
3589   i = 0;
3590   while (i < nid->n_nodes)
3591     {
3592       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
3593         goto out;
3594
3595       ++i;
3596     }
3597
3598   /* if we wrote any typecodes then this would fail */
3599   _dbus_assert (sig_len == _dbus_string_get_length (nid->signature));
3600
3601   /* But be sure we wrote out the values correctly */
3602   i = 0;
3603   while (i < nid->n_nodes)
3604     {
3605       if (!node_read_value (nid->nodes[i], &reader, i))
3606         goto out;
3607
3608       if (i + 1 == nid->n_nodes)
3609         NEXT_EXPECTING_FALSE (&reader);
3610       else
3611         NEXT_EXPECTING_TRUE (&reader);
3612
3613       ++i;
3614     }
3615
3616   retval = TRUE;
3617
3618  out:
3619   data_block_reset (nid->block);
3620   return retval;
3621 }
3622
3623 /* offset the seed for setting, so we set different numbers than
3624  * we originally wrote. Don't offset by a huge number since in
3625  * some cases it's value = possibilities[seed % n_possibilities]
3626  * and we don't want to wrap around. bool_from_seed
3627  * is just seed % 2 even.
3628  */
3629 #define SET_SEED 1
3630 static dbus_bool_t
3631 run_test_set_values (NodeIterationData *nid)
3632 {
3633   DBusTypeReader reader;
3634   DBusTypeReader realign_root;
3635   dbus_bool_t retval;
3636   int i;
3637
3638   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
3639
3640   retval = FALSE;
3641
3642   data_block_init_reader_writer (nid->block,
3643                                  &reader, NULL);
3644
3645   realign_root = reader;
3646
3647   i = 0;
3648   while (i < nid->n_nodes)
3649     {
3650       if (!node_set_value (nid->nodes[i],
3651                            &reader, &realign_root,
3652                            i + SET_SEED))
3653         goto out;
3654
3655       if (i + 1 == nid->n_nodes)
3656         NEXT_EXPECTING_FALSE (&reader);
3657       else
3658         NEXT_EXPECTING_TRUE (&reader);
3659
3660       ++i;
3661     }
3662
3663   /* Check that the new values were set */
3664
3665   reader = realign_root;
3666
3667   i = 0;
3668   while (i < nid->n_nodes)
3669     {
3670       if (!node_read_value (nid->nodes[i], &reader,
3671                             i + SET_SEED))
3672         goto out;
3673
3674       if (i + 1 == nid->n_nodes)
3675         NEXT_EXPECTING_FALSE (&reader);
3676       else
3677         NEXT_EXPECTING_TRUE (&reader);
3678
3679       ++i;
3680     }
3681
3682   retval = TRUE;
3683
3684  out:
3685   return retval;
3686 }
3687
3688 static dbus_bool_t
3689 run_test_delete_values (NodeIterationData *nid)
3690 {
3691   DBusTypeReader reader;
3692   dbus_bool_t retval;
3693   int t;
3694
3695   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
3696
3697   retval = FALSE;
3698
3699   data_block_init_reader_writer (nid->block,
3700                                  &reader, NULL);
3701
3702   while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID)
3703     {
3704       /* Right now, deleting only works on array elements.  We delete
3705        * all array elements, and then verify that there aren't any
3706        * left.
3707        */
3708       if (t == DBUS_TYPE_ARRAY)
3709         {
3710           DBusTypeReader array;
3711           int n_elements;
3712           int elem_type;
3713
3714           _dbus_type_reader_recurse (&reader, &array);
3715           n_elements = 0;
3716           while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID)
3717             {
3718               n_elements += 1;
3719               _dbus_type_reader_next (&array);
3720             }
3721
3722           /* reset to start of array */
3723           _dbus_type_reader_recurse (&reader, &array);
3724           _dbus_verbose ("recursing into deletion loop reader.value_pos = %d array.value_pos = %d array.u.start_pos = %d\n",
3725                          reader.value_pos, array.value_pos, array.u.array.start_pos);
3726           while ((elem_type = _dbus_type_reader_get_current_type (&array)) != DBUS_TYPE_INVALID)
3727             {
3728               /* We don't want to always delete from the same part of the array. */
3729               static int cycle = 0;
3730               int elem;
3731
3732               _dbus_assert (n_elements > 0);
3733               _dbus_assert (!_dbus_type_reader_array_is_empty (&reader));
3734
3735               elem = cycle;
3736               if (elem == 3 || elem >= n_elements) /* end of array */
3737                 elem = n_elements - 1;
3738
3739               _dbus_verbose ("deleting array element %d of %d type %s cycle %d reader pos %d elem pos %d\n",
3740                              elem, n_elements, _dbus_type_to_string (elem_type),
3741                              cycle, reader.value_pos, array.value_pos);
3742               while (elem > 0)
3743                 {
3744                   if (!_dbus_type_reader_next (&array))
3745                     _dbus_assert_not_reached ("should have had another element\n");
3746                   --elem;
3747                 }
3748
3749               if (!_dbus_type_reader_delete (&array, &reader))
3750                 goto out;
3751
3752               n_elements -= 1;
3753
3754               /* reset */
3755               _dbus_type_reader_recurse (&reader, &array);
3756
3757               if (cycle > 2)
3758                 cycle = 0;
3759               else
3760                 cycle += 1;
3761             }
3762         }
3763       _dbus_type_reader_next (&reader);
3764     }
3765
3766   /* Check that there are no array elements left */
3767   data_block_init_reader_writer (nid->block,
3768                                  &reader, NULL);
3769
3770   while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID)
3771     {
3772       if (t == DBUS_TYPE_ARRAY)
3773         _dbus_assert (_dbus_type_reader_array_is_empty (&reader));
3774
3775       _dbus_type_reader_next (&reader);
3776     }
3777
3778   retval = TRUE;
3779
3780  out:
3781   return retval;
3782 }
3783
3784 static dbus_bool_t
3785 run_test_nodes_iteration (void *data)
3786 {
3787   NodeIterationData *nid = data;
3788   DBusTypeReader reader;
3789   DBusTypeWriter writer;
3790   int i;
3791   dbus_bool_t retval;
3792
3793   /* Stuff to do:
3794    * 1. write the value
3795    * 2. strcmp-compare with the signature we built
3796    * 3. read the value
3797    * 4. type-iterate the signature and the value and see if they are the same type-wise
3798    */
3799   retval = FALSE;
3800
3801   data_block_init_reader_writer (nid->block,
3802                                  &reader, &writer);
3803
3804   /* DBusTypeWriter assumes it's writing into an existing signature,
3805    * so doesn't add nul on its own. We have to do that.
3806    */
3807   if (!_dbus_string_insert_byte (&nid->block->signature,
3808                                  nid->type_offset, '\0'))
3809     goto out;
3810
3811   i = 0;
3812   while (i < nid->n_nodes)
3813     {
3814       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
3815         goto out;
3816
3817       ++i;
3818     }
3819
3820   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
3821                                      &nid->block->signature, nid->type_offset))
3822     {
3823       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
3824                   _dbus_string_get_const_data (nid->signature),
3825                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
3826                   nid->type_offset);
3827       _dbus_assert_not_reached ("wrong signature");
3828     }
3829
3830   i = 0;
3831   while (i < nid->n_nodes)
3832     {
3833       if (!node_read_value (nid->nodes[i], &reader, i))
3834         goto out;
3835
3836       if (i + 1 == nid->n_nodes)
3837         NEXT_EXPECTING_FALSE (&reader);
3838       else
3839         NEXT_EXPECTING_TRUE (&reader);
3840
3841       ++i;
3842     }
3843
3844   if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS)
3845     {
3846       /* this set values test uses code from copy and
3847        * values_only_write so would ideally be last so you get a
3848        * simpler test case for problems with copying or values_only
3849        * writing; but it also needs an already-written DataBlock so it
3850        * has to go first. Comment it out if it breaks, and see if the
3851        * later tests also break - debug them first if so.
3852        */
3853       if (!run_test_set_values (nid))
3854         goto out;
3855
3856       if (!run_test_delete_values (nid))
3857         goto out;
3858
3859       if (!run_test_copy (nid))
3860         goto out;
3861
3862       if (!run_test_values_only_write (nid))
3863         goto out;
3864     }
3865
3866   /* FIXME type-iterate both signature and value and compare the resulting
3867    * tree to the node tree perhaps
3868    */
3869
3870   retval = TRUE;
3871
3872  out:
3873
3874   data_block_reset (nid->block);
3875
3876   return retval;
3877 }
3878
3879 static void
3880 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
3881                                      int               n_nodes,
3882                                      const DBusString *signature,
3883                                      int               byte_order,
3884                                      int               initial_offset)
3885 {
3886   DataBlock block;
3887   NodeIterationData nid;
3888
3889   if (!data_block_init (&block, byte_order, initial_offset))
3890     _dbus_assert_not_reached ("no memory");
3891
3892   nid.signature = signature;
3893   nid.block = &block;
3894   nid.type_offset = initial_offset;
3895   nid.nodes = nodes;
3896   nid.n_nodes = n_nodes;
3897
3898   if (TEST_OOM_HANDLING &&
3899       n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS)
3900     {
3901       _dbus_test_oom_handling ("running test node",
3902                                run_test_nodes_iteration,
3903                                &nid);
3904     }
3905   else
3906     {
3907       if (!run_test_nodes_iteration (&nid))
3908         _dbus_assert_not_reached ("no memory");
3909     }
3910
3911   data_block_free (&block);
3912 }
3913
3914 static void
3915 run_test_nodes (TestTypeNode **nodes,
3916                 int            n_nodes)
3917 {
3918   int i;
3919   DBusString signature;
3920
3921   if (!_dbus_string_init (&signature))
3922     _dbus_assert_not_reached ("no memory");
3923
3924   i = 0;
3925   while (i < n_nodes)
3926     {
3927       if (! node_build_signature (nodes[i], &signature))
3928         _dbus_assert_not_reached ("no memory");
3929
3930       ++i;
3931     }
3932
3933   _dbus_verbose (">>> test nodes with signature '%s'\n",
3934                  _dbus_string_get_const_data (&signature));
3935
3936   i = 0;
3937   while (i <= MAX_INITIAL_OFFSET)
3938     {
3939       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
3940                                            DBUS_LITTLE_ENDIAN, i);
3941       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
3942                                            DBUS_BIG_ENDIAN, i);
3943
3944       ++i;
3945     }
3946
3947   n_iterations_completed_this_test += 1;
3948   n_iterations_completed_total += 1;
3949
3950   if (n_iterations_completed_this_test == n_iterations_expected_this_test)
3951     {
3952       fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
3953                n_iterations_completed_this_test,
3954                n_iterations_completed_total);
3955     }
3956   /* this happens to turn out well with mod == 1 */
3957   else if ((n_iterations_completed_this_test %
3958             (int)(n_iterations_expected_this_test / 10.0)) == 1)
3959     {
3960       fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
3961     }
3962
3963   _dbus_string_free (&signature);
3964 }
3965
3966 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
3967
3968 static TestTypeNode*
3969 value_generator (int *ip)
3970 {
3971   int i = *ip;
3972   const TestTypeNodeClass *child_klass;
3973   const TestTypeNodeClass *container_klass;
3974   TestTypeNode *child;
3975   TestTypeNode *node;
3976
3977   _dbus_assert (i <= N_VALUES);
3978
3979   if (i == N_VALUES)
3980     {
3981       return NULL;
3982     }
3983   else if (i < N_BASICS)
3984     {
3985       node = node_new (basic_nodes[i]);
3986     }
3987   else
3988     {
3989       /* imagine an array:
3990        * container 0 of basic 0
3991        * container 0 of basic 1
3992        * container 0 of basic 2
3993        * container 1 of basic 0
3994        * container 1 of basic 1
3995        * container 1 of basic 2
3996        */
3997       i -= N_BASICS;
3998
3999       container_klass = container_nodes[i / N_BASICS];
4000       child_klass = basic_nodes[i % N_BASICS];
4001
4002       node = node_new (container_klass);
4003       child = node_new (child_klass);
4004
4005       node_append_child (node, child);
4006     }
4007
4008   *ip += 1; /* increment the generator */
4009
4010   return node;
4011 }
4012
4013 static void
4014 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
4015                                       int                      n_nested)
4016 {
4017   TestTypeNode *root;
4018   TestTypeNode *container;
4019   TestTypeNode *child;
4020   int i;
4021
4022   root = node_new (container_klass);
4023   container = root;
4024   for (i = 1; i < n_nested; i++)
4025     {
4026       child = node_new (container_klass);
4027       node_append_child (container, child);
4028       container = child;
4029     }
4030
4031   /* container should now be the most-nested container */
4032
4033   i = 0;
4034   while ((child = value_generator (&i)))
4035     {
4036       node_append_child (container, child);
4037
4038       run_test_nodes (&root, 1);
4039
4040       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
4041       node_destroy (child);
4042     }
4043
4044   node_destroy (root);
4045 }
4046
4047 static void
4048 start_next_test (const char *format,
4049                  int         expected)
4050 {
4051   n_iterations_completed_this_test = 0;
4052   n_iterations_expected_this_test = expected;
4053
4054   fprintf (stderr, ">>> >>> ");
4055   fprintf (stderr, format,
4056            n_iterations_expected_this_test);
4057 }
4058
4059 static void
4060 make_and_run_test_nodes (void)
4061 {
4062   int i, j, k, m;
4063
4064   /* We try to do this in order of "complicatedness" so that test
4065    * failures tend to show up in the simplest test case that
4066    * demonstrates the failure.  There are also some tests that run
4067    * more than once for this reason, first while going through simple
4068    * cases, second while going through a broader range of complex
4069    * cases.
4070    */
4071   /* Each basic node. The basic nodes should include:
4072    *
4073    * - each fixed-size type (in such a way that it has different values each time,
4074    *                         so we can tell if we mix two of them up)
4075    * - strings of various lengths
4076    * - object path
4077    * - signature
4078    */
4079   /* Each container node. The container nodes should include:
4080    *
4081    *  struct with 1 and 2 copies of the contained item
4082    *  array with 0, 1, 2 copies of the contained item
4083    *  variant
4084    */
4085   /*  Let a "value" be a basic node, or a container containing a single basic node.
4086    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
4087    *  When iterating through all values to make combinations, do the basic types
4088    *  first and the containers second.
4089    */
4090   /* Each item is shown with its number of iterations to complete so
4091    * we can keep a handle on this unit test
4092    */
4093
4094   /* FIXME test just an empty body, no types at all */
4095
4096   start_next_test ("Each value by itself %d iterations\n", N_VALUES);
4097   {
4098     TestTypeNode *node;
4099     i = 0;
4100     while ((node = value_generator (&i)))
4101       {
4102         run_test_nodes (&node, 1);
4103
4104         node_destroy (node);
4105       }
4106   }
4107
4108   start_next_test ("Each value by itself with arrays as blocks %d iterations\n", N_VALUES);
4109   arrays_write_fixed_in_blocks = TRUE;
4110   {
4111     TestTypeNode *node;
4112     i = 0;
4113     while ((node = value_generator (&i)))
4114       {
4115         run_test_nodes (&node, 1);
4116
4117         node_destroy (node);
4118       }
4119   }
4120   arrays_write_fixed_in_blocks = FALSE;
4121
4122   start_next_test ("All values in one big toplevel %d iteration\n", 1);
4123   {
4124     TestTypeNode *nodes[N_VALUES];
4125
4126     i = 0;
4127     while ((nodes[i] = value_generator (&i)))
4128       ;
4129
4130     run_test_nodes (nodes, N_VALUES);
4131
4132     for (i = 0; i < N_VALUES; i++)
4133       node_destroy (nodes[i]);
4134   }
4135
4136   start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
4137                    N_VALUES * N_VALUES);
4138   {
4139     TestTypeNode *nodes[2];
4140
4141     i = 0;
4142     while ((nodes[0] = value_generator (&i)))
4143       {
4144         j = 0;
4145         while ((nodes[1] = value_generator (&j)))
4146           {
4147             run_test_nodes (nodes, 2);
4148
4149             node_destroy (nodes[1]);
4150           }
4151
4152         node_destroy (nodes[0]);
4153       }
4154   }
4155
4156   start_next_test ("Each container containing each value %d iterations\n",
4157                    N_CONTAINERS * N_VALUES);
4158   for (i = 0; i < N_CONTAINERS; i++)
4159     {
4160       const TestTypeNodeClass *container_klass = container_nodes[i];
4161
4162       make_and_run_values_inside_container (container_klass, 1);
4163     }
4164
4165   start_next_test ("Each container containing each value with arrays as blocks %d iterations\n",
4166                    N_CONTAINERS * N_VALUES);
4167   arrays_write_fixed_in_blocks = TRUE;
4168   for (i = 0; i < N_CONTAINERS; i++)
4169     {
4170       const TestTypeNodeClass *container_klass = container_nodes[i];
4171
4172       make_and_run_values_inside_container (container_klass, 1);
4173     }
4174   arrays_write_fixed_in_blocks = FALSE;
4175
4176   start_next_test ("Each container of same container of each value %d iterations\n",
4177                    N_CONTAINERS * N_VALUES);
4178   for (i = 0; i < N_CONTAINERS; i++)
4179     {
4180       const TestTypeNodeClass *container_klass = container_nodes[i];
4181
4182       make_and_run_values_inside_container (container_klass, 2);
4183     }
4184
4185   start_next_test ("Each container of same container of same container of each value %d iterations\n",
4186                    N_CONTAINERS * N_VALUES);
4187   for (i = 0; i < N_CONTAINERS; i++)
4188     {
4189       const TestTypeNodeClass *container_klass = container_nodes[i];
4190
4191       make_and_run_values_inside_container (container_klass, 3);
4192     }
4193
4194   start_next_test ("Each value,value pair inside a struct %d iterations\n",
4195                    N_VALUES * N_VALUES);
4196   {
4197     TestTypeNode *val1, *val2;
4198     TestTypeNode *node;
4199
4200     node = node_new (&struct_1_class);
4201
4202     i = 0;
4203     while ((val1 = value_generator (&i)))
4204       {
4205         j = 0;
4206         while ((val2 = value_generator (&j)))
4207           {
4208             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4209
4210             node_append_child (node, val1);
4211             node_append_child (node, val2);
4212
4213             run_test_nodes (&node, 1);
4214
4215             _dbus_list_clear (&container->children);
4216             node_destroy (val2);
4217           }
4218         node_destroy (val1);
4219       }
4220     node_destroy (node);
4221   }
4222
4223   start_next_test ("All values in one big struct %d iteration\n",
4224                    1);
4225   {
4226     TestTypeNode *node;
4227     TestTypeNode *child;
4228
4229     node = node_new (&struct_1_class);
4230
4231     i = 0;
4232     while ((child = value_generator (&i)))
4233       node_append_child (node, child);
4234
4235     run_test_nodes (&node, 1);
4236
4237     node_destroy (node);
4238   }
4239
4240   start_next_test ("Each value in a large array %d iterations\n",
4241                    N_VALUES);
4242   {
4243     TestTypeNode *val;
4244     TestTypeNode *node;
4245
4246     node = node_new (&array_9_class);
4247
4248     i = 0;
4249     while ((val = value_generator (&i)))
4250       {
4251         TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4252
4253         node_append_child (node, val);
4254
4255         run_test_nodes (&node, 1);
4256
4257         _dbus_list_clear (&container->children);
4258         node_destroy (val);
4259       }
4260
4261     node_destroy (node);
4262   }
4263
4264   start_next_test ("Each container of each container of each value %d iterations\n",
4265                    N_CONTAINERS * N_CONTAINERS * N_VALUES);
4266   for (i = 0; i < N_CONTAINERS; i++)
4267     {
4268       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
4269       TestTypeNode *outer_container = node_new (outer_container_klass);
4270
4271       for (j = 0; j < N_CONTAINERS; j++)
4272         {
4273           TestTypeNode *child;
4274           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
4275           TestTypeNode *inner_container = node_new (inner_container_klass);
4276
4277           node_append_child (outer_container, inner_container);
4278
4279           m = 0;
4280           while ((child = value_generator (&m)))
4281             {
4282               node_append_child (inner_container, child);
4283
4284               run_test_nodes (&outer_container, 1);
4285
4286               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
4287               node_destroy (child);
4288             }
4289           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
4290           node_destroy (inner_container);
4291         }
4292       node_destroy (outer_container);
4293     }
4294
4295   start_next_test ("Each container of each container of each container of each value %d iterations\n",
4296                    N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
4297   for (i = 0; i < N_CONTAINERS; i++)
4298     {
4299       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
4300       TestTypeNode *outer_container = node_new (outer_container_klass);
4301
4302       for (j = 0; j < N_CONTAINERS; j++)
4303         {
4304           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
4305           TestTypeNode *inner_container = node_new (inner_container_klass);
4306
4307           node_append_child (outer_container, inner_container);
4308
4309           for (k = 0; k < N_CONTAINERS; k++)
4310             {
4311               TestTypeNode *child;
4312               const TestTypeNodeClass *center_container_klass = container_nodes[k];
4313               TestTypeNode *center_container = node_new (center_container_klass);
4314
4315               node_append_child (inner_container, center_container);
4316
4317               m = 0;
4318               while ((child = value_generator (&m)))
4319                 {
4320                   node_append_child (center_container, child);
4321
4322                   run_test_nodes (&outer_container, 1);
4323
4324                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
4325                   node_destroy (child);
4326                 }
4327               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
4328               node_destroy (center_container);
4329             }
4330           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
4331           node_destroy (inner_container);
4332         }
4333       node_destroy (outer_container);
4334     }
4335
4336 #if 0
4337   /* This one takes a really long time, so comment it out for now */
4338   start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
4339                    N_VALUES * N_VALUES * N_VALUES);
4340   {
4341     TestTypeNode *nodes[3];
4342
4343     i = 0;
4344     while ((nodes[0] = value_generator (&i)))
4345       {
4346         j = 0;
4347         while ((nodes[1] = value_generator (&j)))
4348           {
4349             k = 0;
4350             while ((nodes[2] = value_generator (&k)))
4351               {
4352                 run_test_nodes (nodes, 3);
4353
4354                 node_destroy (nodes[2]);
4355               }
4356             node_destroy (nodes[1]);
4357           }
4358         node_destroy (nodes[0]);
4359       }
4360   }
4361 #endif /* #if 0 expensive test */
4362
4363   fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
4364            n_iterations_completed_total);
4365   fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
4366            MAX_INITIAL_OFFSET);
4367   fprintf (stderr, "out of memory handling %s tested\n",
4368            TEST_OOM_HANDLING ? "was" : "was not");
4369 }
4370
4371 dbus_bool_t
4372 _dbus_marshal_recursive_test (void)
4373 {
4374   make_and_run_test_nodes ();
4375
4376   return TRUE;
4377 }
4378
4379 /*
4380  *
4381  *
4382  *         Implementations of each type node class
4383  *
4384  *
4385  *
4386  */
4387 #define MAX_MULTI_COUNT 5
4388
4389
4390 #define SAMPLE_INT32           12345678
4391 #define SAMPLE_INT32_ALTERNATE 53781429
4392 static dbus_int32_t
4393 int32_from_seed (int seed)
4394 {
4395   /* Generate an integer value that's predictable from seed.  We could
4396    * just use seed itself, but that would only ever touch one byte of
4397    * the int so would miss some kinds of bug.
4398    */
4399   dbus_int32_t v;
4400
4401   v = 42; /* just to quiet compiler afaik */
4402   switch (seed % 5)
4403     {
4404     case 0:
4405       v = SAMPLE_INT32;
4406       break;
4407     case 1:
4408       v = SAMPLE_INT32_ALTERNATE;
4409       break;
4410     case 2:
4411       v = -1;
4412       break;
4413     case 3:
4414       v = _DBUS_INT_MAX;
4415       break;
4416     case 4:
4417       v = 1;
4418       break;
4419     }
4420
4421   if (seed > 1)
4422     v *= seed; /* wraps around eventually, which is fine */
4423
4424   return v;
4425 }
4426
4427 static dbus_bool_t
4428 int32_write_value (TestTypeNode   *node,
4429                    DataBlock      *block,
4430                    DBusTypeWriter *writer,
4431                    int             seed)
4432 {
4433   /* also used for uint32 */
4434   dbus_int32_t v;
4435
4436   v = int32_from_seed (seed);
4437
4438   return _dbus_type_writer_write_basic (writer,
4439                                         node->klass->typecode,
4440                                         &v);
4441 }
4442
4443 static dbus_bool_t
4444 int32_read_value (TestTypeNode   *node,
4445                   DBusTypeReader *reader,
4446                   int             seed)
4447 {
4448   /* also used for uint32 */
4449   dbus_int32_t v;
4450
4451   check_expected_type (reader, node->klass->typecode);
4452
4453   _dbus_type_reader_read_basic (reader,
4454                                 (dbus_int32_t*) &v);
4455
4456   _dbus_assert (v == int32_from_seed (seed));
4457
4458   return TRUE;
4459 }
4460
4461 static dbus_bool_t
4462 int32_set_value (TestTypeNode   *node,
4463                  DBusTypeReader *reader,
4464                  DBusTypeReader *realign_root,
4465                  int             seed)
4466 {
4467   /* also used for uint32 */
4468   dbus_int32_t v;
4469
4470   v = int32_from_seed (seed);
4471
4472   return _dbus_type_reader_set_basic (reader,
4473                                       &v,
4474                                       realign_root);
4475 }
4476
4477 static dbus_bool_t
4478 int32_write_multi (TestTypeNode   *node,
4479                    DataBlock      *block,
4480                    DBusTypeWriter *writer,
4481                    int             seed,
4482                    int             count)
4483 {
4484   /* also used for uint32 */
4485   dbus_int32_t values[MAX_MULTI_COUNT];
4486   dbus_int32_t *v_ARRAY_INT32 = values;
4487   int i;
4488
4489   for (i = 0; i < count; ++i)
4490     values[i] = int32_from_seed (seed + i);
4491
4492   return _dbus_type_writer_write_fixed_multi (writer,
4493                                               node->klass->typecode,
4494                                               &v_ARRAY_INT32, count);
4495 }
4496
4497 static dbus_bool_t
4498 int32_read_multi (TestTypeNode   *node,
4499                   DBusTypeReader *reader,
4500                   int             seed,
4501                   int             count)
4502 {
4503   /* also used for uint32 */
4504   dbus_int32_t *values;
4505   int n_elements;
4506   int i;
4507
4508   check_expected_type (reader, node->klass->typecode);
4509
4510   _dbus_type_reader_read_fixed_multi (reader,
4511                                       &values,
4512                                       &n_elements);
4513
4514   if (n_elements != count)
4515     _dbus_warn ("got %d elements expected %d\n", n_elements, count);
4516   _dbus_assert (n_elements == count);
4517
4518   for (i = 0; i < count; i++)
4519     _dbus_assert (_dbus_unpack_int32 (reader->byte_order,
4520                                       (const unsigned char*)values + (i * 4)) ==
4521                   int32_from_seed (seed + i));
4522
4523   return TRUE;
4524 }
4525
4526 #ifdef DBUS_HAVE_INT64
4527 static dbus_int64_t
4528 int64_from_seed (int seed)
4529 {
4530   dbus_int32_t v32;
4531   dbus_int64_t v;
4532
4533   v32 = int32_from_seed (seed);
4534
4535   v = - (dbus_int32_t) ~ v32;
4536   v |= (((dbus_int64_t)v32) << 32);
4537
4538   return v;
4539 }
4540 #endif
4541
4542 static dbus_bool_t
4543 int64_write_value (TestTypeNode   *node,
4544                    DataBlock      *block,
4545                    DBusTypeWriter *writer,
4546                    int             seed)
4547 {
4548 #ifdef DBUS_HAVE_INT64
4549   /* also used for uint64 */
4550   dbus_int64_t v;
4551
4552   v = int64_from_seed (seed);
4553
4554   return _dbus_type_writer_write_basic (writer,
4555                                         node->klass->typecode,
4556                                         &v);
4557 #else
4558   return TRUE;
4559 #endif
4560 }
4561
4562 static dbus_bool_t
4563 int64_read_value (TestTypeNode   *node,
4564                   DBusTypeReader *reader,
4565                   int             seed)
4566 {
4567 #ifdef DBUS_HAVE_INT64
4568   /* also used for uint64 */
4569   dbus_int64_t v;
4570
4571   check_expected_type (reader, node->klass->typecode);
4572
4573   _dbus_type_reader_read_basic (reader,
4574                                 (dbus_int64_t*) &v);
4575
4576   _dbus_assert (v == int64_from_seed (seed));
4577
4578   return TRUE;
4579 #else
4580   return TRUE;
4581 #endif
4582 }
4583
4584 static dbus_bool_t
4585 int64_set_value (TestTypeNode   *node,
4586                  DBusTypeReader *reader,
4587                  DBusTypeReader *realign_root,
4588                  int             seed)
4589 {
4590 #ifdef DBUS_HAVE_INT64
4591   /* also used for uint64 */
4592   dbus_int64_t v;
4593
4594   v = int64_from_seed (seed);
4595
4596   return _dbus_type_reader_set_basic (reader,
4597                                       &v,
4598                                       realign_root);
4599 #else
4600   return TRUE;
4601 #endif
4602 }
4603
4604 #define MAX_SAMPLE_STRING_LEN 10
4605 static void
4606 string_from_seed (char *buf,
4607                   int   len,
4608                   int   seed)
4609 {
4610   int i;
4611   unsigned char v;
4612
4613   _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
4614
4615   /* vary the length slightly, though we also have multiple string
4616    * value types for this, varying it here tests the set_value code
4617    */
4618   switch (seed % 3)
4619     {
4620     case 1:
4621       len += 2;
4622       break;
4623     case 2:
4624       len -= 2;
4625       break;
4626     }
4627   if (len < 0)
4628     len = 0;
4629
4630   v = (unsigned char) ('A' + seed);
4631
4632   i = 0;
4633   while (i < len)
4634     {
4635       if (v < 'A' || v > 'z')
4636         v = 'A';
4637
4638       buf[i] = v;
4639
4640       v += 1;
4641       ++i;
4642     }
4643
4644   buf[i] = '\0';
4645 }
4646
4647 static dbus_bool_t
4648 string_write_value (TestTypeNode   *node,
4649                     DataBlock      *block,
4650                     DBusTypeWriter *writer,
4651                     int             seed)
4652 {
4653   char buf[MAX_SAMPLE_STRING_LEN];
4654   const char *v_string = buf;
4655
4656   string_from_seed (buf, node->klass->subclass_detail,
4657                     seed);
4658
4659   return _dbus_type_writer_write_basic (writer,
4660                                         node->klass->typecode,
4661                                         &v_string);
4662 }
4663
4664 static dbus_bool_t
4665 string_read_value (TestTypeNode   *node,
4666                    DBusTypeReader *reader,
4667                    int             seed)
4668 {
4669   const char *v;
4670   char buf[MAX_SAMPLE_STRING_LEN];
4671
4672   check_expected_type (reader, node->klass->typecode);
4673
4674   _dbus_type_reader_read_basic (reader,
4675                                 (const char **) &v);
4676
4677   string_from_seed (buf, node->klass->subclass_detail,
4678                     seed);
4679
4680   if (strcmp (buf, v) != 0)
4681     {
4682       _dbus_warn ("read string '%s' expected '%s'\n",
4683                   v, buf);
4684       _dbus_assert_not_reached ("test failed");
4685     }
4686
4687   return TRUE;
4688 }
4689
4690 static dbus_bool_t
4691 string_set_value (TestTypeNode   *node,
4692                   DBusTypeReader *reader,
4693                   DBusTypeReader *realign_root,
4694                   int             seed)
4695 {
4696   char buf[MAX_SAMPLE_STRING_LEN];
4697   const char *v_string = buf;
4698
4699   string_from_seed (buf, node->klass->subclass_detail,
4700                     seed);
4701
4702 #if RECURSIVE_MARSHAL_WRITE_TRACE
4703  {
4704    const char *old;
4705    _dbus_type_reader_read_basic (reader, &old);
4706    _dbus_verbose ("SETTING new string '%s' len %d in place of '%s' len %d\n",
4707                   v_string, strlen (v_string), old, strlen (old));
4708  }
4709 #endif
4710
4711   return _dbus_type_reader_set_basic (reader,
4712                                       &v_string,
4713                                       realign_root);
4714 }
4715
4716 #define BOOL_FROM_SEED(seed) (seed % 2)
4717
4718 static dbus_bool_t
4719 bool_write_value (TestTypeNode   *node,
4720                   DataBlock      *block,
4721                   DBusTypeWriter *writer,
4722                   int             seed)
4723 {
4724   unsigned char v;
4725
4726   v = BOOL_FROM_SEED (seed);
4727
4728   return _dbus_type_writer_write_basic (writer,
4729                                         node->klass->typecode,
4730                                         &v);
4731 }
4732
4733 static dbus_bool_t
4734 bool_read_value (TestTypeNode   *node,
4735                  DBusTypeReader *reader,
4736                  int             seed)
4737 {
4738   unsigned char v;
4739
4740   check_expected_type (reader, node->klass->typecode);
4741
4742   _dbus_type_reader_read_basic (reader,
4743                                 (unsigned char*) &v);
4744
4745   _dbus_assert (v == BOOL_FROM_SEED (seed));
4746
4747   return TRUE;
4748 }
4749
4750 static dbus_bool_t
4751 bool_set_value (TestTypeNode   *node,
4752                 DBusTypeReader *reader,
4753                 DBusTypeReader *realign_root,
4754                 int             seed)
4755 {
4756   unsigned char v;
4757
4758   v = BOOL_FROM_SEED (seed);
4759
4760   return _dbus_type_reader_set_basic (reader,
4761                                       &v,
4762                                       realign_root);
4763 }
4764
4765 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
4766
4767 static dbus_bool_t
4768 byte_write_value (TestTypeNode   *node,
4769                   DataBlock      *block,
4770                   DBusTypeWriter *writer,
4771                   int             seed)
4772 {
4773   unsigned char v;
4774
4775   v = BYTE_FROM_SEED (seed);
4776
4777   return _dbus_type_writer_write_basic (writer,
4778                                         node->klass->typecode,
4779                                         &v);
4780 }
4781
4782 static dbus_bool_t
4783 byte_read_value (TestTypeNode   *node,
4784                  DBusTypeReader *reader,
4785                  int             seed)
4786 {
4787   unsigned char v;
4788
4789   check_expected_type (reader, node->klass->typecode);
4790
4791   _dbus_type_reader_read_basic (reader,
4792                                 (unsigned char*) &v);
4793
4794   _dbus_assert (v == BYTE_FROM_SEED (seed));
4795
4796   return TRUE;
4797 }
4798
4799
4800 static dbus_bool_t
4801 byte_set_value (TestTypeNode   *node,
4802                 DBusTypeReader *reader,
4803                 DBusTypeReader *realign_root,
4804                 int             seed)
4805 {
4806   unsigned char v;
4807
4808   v = BYTE_FROM_SEED (seed);
4809
4810   return _dbus_type_reader_set_basic (reader,
4811                                       &v,
4812                                       realign_root);
4813 }
4814
4815 static double
4816 double_from_seed (int seed)
4817 {
4818   return SAMPLE_INT32 * (double) seed + 0.3;
4819 }
4820
4821 static dbus_bool_t
4822 double_write_value (TestTypeNode   *node,
4823                     DataBlock      *block,
4824                     DBusTypeWriter *writer,
4825                     int             seed)
4826 {
4827   double v;
4828
4829   v = double_from_seed (seed);
4830
4831   return _dbus_type_writer_write_basic (writer,
4832                                         node->klass->typecode,
4833                                         &v);
4834 }
4835
4836 static dbus_bool_t
4837 double_read_value (TestTypeNode   *node,
4838                    DBusTypeReader *reader,
4839                    int             seed)
4840 {
4841   double v;
4842   double expected;
4843
4844   check_expected_type (reader, node->klass->typecode);
4845
4846   _dbus_type_reader_read_basic (reader,
4847                                 (double*) &v);
4848
4849   expected = double_from_seed (seed);
4850
4851   if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
4852     {
4853 #ifdef DBUS_HAVE_INT64
4854       _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
4855                   expected, v,
4856                   *(dbus_uint64_t*)(char*)&expected,
4857                   *(dbus_uint64_t*)(char*)&v);
4858 #endif
4859       _dbus_assert_not_reached ("test failed");
4860     }
4861
4862   return TRUE;
4863 }
4864
4865 static dbus_bool_t
4866 double_set_value (TestTypeNode   *node,
4867                 DBusTypeReader *reader,
4868                 DBusTypeReader *realign_root,
4869                 int             seed)
4870 {
4871   double v;
4872
4873   v = double_from_seed (seed);
4874
4875   return _dbus_type_reader_set_basic (reader,
4876                                       &v,
4877                                       realign_root);
4878 }
4879
4880 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
4881 static void
4882 object_path_from_seed (char *buf,
4883                        int   seed)
4884 {
4885   int i;
4886   unsigned char v;
4887   int len;
4888
4889   len = seed % 9;
4890   _dbus_assert (len < MAX_SAMPLE_OBJECT_PATH_LEN);
4891
4892   v = (unsigned char) ('A' + seed);
4893
4894   i = 0;
4895   while (i + 1 < len)
4896     {
4897       if (v < 'A' || v > 'z')
4898         v = 'A';
4899
4900       buf[i] = '/';
4901       ++i;
4902       buf[i] = v;
4903       ++i;
4904
4905       v += 1;
4906     }
4907
4908   buf[i] = '\0';
4909 }
4910
4911 static dbus_bool_t
4912 object_path_write_value (TestTypeNode   *node,
4913                          DataBlock      *block,
4914                          DBusTypeWriter *writer,
4915                          int             seed)
4916 {
4917   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
4918   const char *v_string = buf;
4919
4920   object_path_from_seed (buf, seed);
4921
4922   return _dbus_type_writer_write_basic (writer,
4923                                         node->klass->typecode,
4924                                         &v_string);
4925 }
4926
4927 static dbus_bool_t
4928 object_path_read_value (TestTypeNode   *node,
4929                         DBusTypeReader *reader,
4930                         int             seed)
4931 {
4932   const char *v;
4933   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
4934
4935   check_expected_type (reader, node->klass->typecode);
4936
4937   _dbus_type_reader_read_basic (reader,
4938                                 (const char **) &v);
4939
4940   object_path_from_seed (buf, seed);
4941
4942   if (strcmp (buf, v) != 0)
4943     {
4944       _dbus_warn ("read object path '%s' expected '%s'\n",
4945                   v, buf);
4946       _dbus_assert_not_reached ("test failed");
4947     }
4948
4949   return TRUE;
4950 }
4951
4952 static dbus_bool_t
4953 object_path_set_value (TestTypeNode   *node,
4954                        DBusTypeReader *reader,
4955                        DBusTypeReader *realign_root,
4956                        int             seed)
4957 {
4958   char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
4959   const char *v_string = buf;
4960
4961   object_path_from_seed (buf, seed);
4962
4963   return _dbus_type_reader_set_basic (reader,
4964                                       &v_string,
4965                                       realign_root);
4966 }
4967
4968 #define MAX_SAMPLE_SIGNATURE_LEN 10
4969 static void
4970 signature_from_seed (char *buf,
4971                      int   seed)
4972 {
4973   int i;
4974   const char *s;
4975   /* try to avoid ascending, descending, or alternating length to help find bugs */
4976   const char *sample_signatures[] = {
4977     "asax"
4978     "",
4979     "asau(xxxx)",
4980     "x",
4981     "ai",
4982     "a(ii)"
4983   };
4984
4985   s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
4986
4987   for (i = 0; s[i]; i++)
4988     {
4989       buf[i] = s[i];
4990     }
4991   buf[i] = '\0';
4992 }
4993
4994 static dbus_bool_t
4995 signature_write_value (TestTypeNode   *node,
4996                        DataBlock      *block,
4997                        DBusTypeWriter *writer,
4998                        int             seed)
4999 {
5000   char buf[MAX_SAMPLE_SIGNATURE_LEN];
5001   const char *v_string = buf;
5002
5003   signature_from_seed (buf, seed);
5004
5005   return _dbus_type_writer_write_basic (writer,
5006                                         node->klass->typecode,
5007                                         &v_string);
5008 }
5009
5010 static dbus_bool_t
5011 signature_read_value (TestTypeNode   *node,
5012                       DBusTypeReader *reader,
5013                       int             seed)
5014 {
5015   const char *v;
5016   char buf[MAX_SAMPLE_SIGNATURE_LEN];
5017
5018   check_expected_type (reader, node->klass->typecode);
5019
5020   _dbus_type_reader_read_basic (reader,
5021                                 (const char **) &v);
5022
5023   signature_from_seed (buf, seed);
5024
5025   if (strcmp (buf, v) != 0)
5026     {
5027       _dbus_warn ("read signature value '%s' expected '%s'\n",
5028                   v, buf);
5029       _dbus_assert_not_reached ("test failed");
5030     }
5031
5032   return TRUE;
5033 }
5034
5035
5036 static dbus_bool_t
5037 signature_set_value (TestTypeNode   *node,
5038                      DBusTypeReader *reader,
5039                      DBusTypeReader *realign_root,
5040                      int             seed)
5041 {
5042   char buf[MAX_SAMPLE_SIGNATURE_LEN];
5043   const char *v_string = buf;
5044
5045   signature_from_seed (buf, seed);
5046
5047   return _dbus_type_reader_set_basic (reader,
5048                                       &v_string,
5049                                       realign_root);
5050 }
5051
5052 static dbus_bool_t
5053 struct_write_value (TestTypeNode   *node,
5054                     DataBlock      *block,
5055                     DBusTypeWriter *writer,
5056                     int             seed)
5057 {
5058   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5059   DataBlockState saved;
5060   DBusTypeWriter sub;
5061   int i;
5062   int n_copies;
5063
5064   n_copies = node->klass->subclass_detail;
5065
5066   _dbus_assert (container->children != NULL);
5067
5068   data_block_save (block, &saved);
5069
5070   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT,
5071                                   NULL, 0,
5072                                   &sub))
5073     return FALSE;
5074
5075   i = 0;
5076   while (i < n_copies)
5077     {
5078       DBusList *link;
5079
5080       link = _dbus_list_get_first_link (&container->children);
5081       while (link != NULL)
5082         {
5083           TestTypeNode *child = link->data;
5084           DBusList *next = _dbus_list_get_next_link (&container->children, link);
5085
5086           if (!node_write_value (child, block, &sub, seed + i))
5087             {
5088               data_block_restore (block, &saved);
5089               return FALSE;
5090             }
5091
5092           link = next;
5093         }
5094
5095       ++i;
5096     }
5097
5098   if (!_dbus_type_writer_unrecurse (writer, &sub))
5099     {
5100       data_block_restore (block, &saved);
5101       return FALSE;
5102     }
5103
5104   return TRUE;
5105 }
5106
5107 static dbus_bool_t
5108 struct_read_or_set_value (TestTypeNode   *node,
5109                           DBusTypeReader *reader,
5110                           DBusTypeReader *realign_root,
5111                           int             seed)
5112 {
5113   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5114   DBusTypeReader sub;
5115   int i;
5116   int n_copies;
5117
5118   n_copies = node->klass->subclass_detail;
5119
5120   check_expected_type (reader, DBUS_TYPE_STRUCT);
5121
5122   _dbus_type_reader_recurse (reader, &sub);
5123
5124   i = 0;
5125   while (i < n_copies)
5126     {
5127       DBusList *link;
5128
5129       link = _dbus_list_get_first_link (&container->children);
5130       while (link != NULL)
5131         {
5132           TestTypeNode *child = link->data;
5133           DBusList *next = _dbus_list_get_next_link (&container->children, link);
5134
5135           if (realign_root == NULL)
5136             {
5137               if (!node_read_value (child, &sub, seed + i))
5138                 return FALSE;
5139             }
5140           else
5141             {
5142               if (!node_set_value (child, &sub, realign_root, seed + i))
5143                 return FALSE;
5144             }
5145
5146           if (i == (n_copies - 1) && next == NULL)
5147             NEXT_EXPECTING_FALSE (&sub);
5148           else
5149             NEXT_EXPECTING_TRUE (&sub);
5150
5151           link = next;
5152         }
5153
5154       ++i;
5155     }
5156
5157   return TRUE;
5158 }
5159
5160 static dbus_bool_t
5161 struct_read_value (TestTypeNode   *node,
5162                    DBusTypeReader *reader,
5163                    int             seed)
5164 {
5165   return struct_read_or_set_value (node, reader, NULL, seed);
5166 }
5167
5168 static dbus_bool_t
5169 struct_set_value (TestTypeNode   *node,
5170                   DBusTypeReader *reader,
5171                   DBusTypeReader *realign_root,
5172                   int             seed)
5173 {
5174   return struct_read_or_set_value (node, reader, realign_root, seed);
5175 }
5176
5177 static dbus_bool_t
5178 struct_build_signature (TestTypeNode   *node,
5179                         DBusString     *str)
5180 {
5181   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5182   int i;
5183   int orig_len;
5184   int n_copies;
5185
5186   n_copies = node->klass->subclass_detail;
5187
5188   orig_len = _dbus_string_get_length (str);
5189
5190   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
5191     goto oom;
5192
5193   i = 0;
5194   while (i < n_copies)
5195     {
5196       DBusList *link;
5197
5198       link = _dbus_list_get_first_link (&container->children);
5199       while (link != NULL)
5200         {
5201           TestTypeNode *child = link->data;
5202           DBusList *next = _dbus_list_get_next_link (&container->children, link);
5203
5204           if (!node_build_signature (child, str))
5205             goto oom;
5206
5207           link = next;
5208         }
5209
5210       ++i;
5211     }
5212
5213   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
5214     goto oom;
5215
5216   return TRUE;
5217
5218  oom:
5219   _dbus_string_set_length (str, orig_len);
5220   return FALSE;
5221 }
5222
5223 static dbus_bool_t
5224 array_write_value (TestTypeNode   *node,
5225                    DataBlock      *block,
5226                    DBusTypeWriter *writer,
5227                    int             seed)
5228 {
5229   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5230   DataBlockState saved;
5231   DBusTypeWriter sub;
5232   DBusString element_signature;
5233   int i;
5234   int n_copies;
5235   int element_type;
5236   TestTypeNode *child;
5237
5238   n_copies = node->klass->subclass_detail;
5239
5240   _dbus_assert (container->children != NULL);
5241
5242   data_block_save (block, &saved);
5243
5244   if (!_dbus_string_init (&element_signature))
5245     return FALSE;
5246
5247   child = _dbus_list_get_first (&container->children);
5248
5249   if (!node_build_signature (child,
5250                              &element_signature))
5251     goto oom;
5252
5253   element_type = first_type_in_signature (&element_signature, 0);
5254
5255   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
5256                                   &element_signature, 0,
5257                                   &sub))
5258     goto oom;
5259
5260   if (arrays_write_fixed_in_blocks &&
5261       _dbus_type_is_fixed (element_type) &&
5262       child->klass->write_multi)
5263     {
5264       if (!node_write_multi (child, block, &sub, seed, n_copies))
5265         goto oom;
5266     }
5267   else
5268     {
5269       i = 0;
5270       while (i < n_copies)
5271         {
5272           DBusList *link;
5273
5274           link = _dbus_list_get_first_link (&container->children);
5275           while (link != NULL)
5276             {
5277               TestTypeNode *child = link->data;
5278               DBusList *next = _dbus_list_get_next_link (&container->children, link);
5279
5280               if (!node_write_value (child, block, &sub, seed + i))
5281                 goto oom;
5282
5283               link = next;
5284             }
5285
5286           ++i;
5287         }
5288     }
5289
5290   if (!_dbus_type_writer_unrecurse (writer, &sub))
5291     goto oom;
5292
5293   _dbus_string_free (&element_signature);
5294   return TRUE;
5295
5296  oom:
5297   data_block_restore (block, &saved);
5298   _dbus_string_free (&element_signature);
5299   return FALSE;
5300 }
5301
5302 static dbus_bool_t
5303 array_read_or_set_value (TestTypeNode   *node,
5304                          DBusTypeReader *reader,
5305                          DBusTypeReader *realign_root,
5306                          int             seed)
5307 {
5308   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5309   DBusTypeReader sub;
5310   int i;
5311   int n_copies;
5312   TestTypeNode *child;
5313
5314   n_copies = node->klass->subclass_detail;
5315
5316   check_expected_type (reader, DBUS_TYPE_ARRAY);
5317
5318   child = _dbus_list_get_first (&container->children);
5319
5320   if (n_copies > 0)
5321     {
5322       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
5323
5324       _dbus_type_reader_recurse (reader, &sub);
5325
5326       if (realign_root == NULL && arrays_write_fixed_in_blocks &&
5327           _dbus_type_is_fixed (_dbus_type_reader_get_array_type (reader)) &&
5328           child->klass->read_multi)
5329         {
5330           if (!node_read_multi (child, &sub, seed, n_copies))
5331             return FALSE;
5332         }
5333       else
5334         {
5335           i = 0;
5336           while (i < n_copies)
5337             {
5338               DBusList *link;
5339
5340               link = _dbus_list_get_first_link (&container->children);
5341               while (link != NULL)
5342                 {
5343                   TestTypeNode *child = link->data;
5344                   DBusList *next = _dbus_list_get_next_link (&container->children, link);
5345
5346                   _dbus_assert (child->klass->typecode ==
5347                                 _dbus_type_reader_get_array_type (reader));
5348
5349                   if (realign_root == NULL)
5350                     {
5351                       if (!node_read_value (child, &sub, seed + i))
5352                         return FALSE;
5353                     }
5354                   else
5355                     {
5356                       if (!node_set_value (child, &sub, realign_root, seed + i))
5357                         return FALSE;
5358                     }
5359
5360                   if (i == (n_copies - 1) && next == NULL)
5361                     NEXT_EXPECTING_FALSE (&sub);
5362                   else
5363                     NEXT_EXPECTING_TRUE (&sub);
5364
5365                   link = next;
5366                 }
5367
5368               ++i;
5369             }
5370         }
5371     }
5372   else
5373     {
5374       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
5375     }
5376
5377   return TRUE;
5378 }
5379
5380 static dbus_bool_t
5381 array_read_value (TestTypeNode   *node,
5382                   DBusTypeReader *reader,
5383                   int             seed)
5384 {
5385   return array_read_or_set_value (node, reader, NULL, seed);
5386 }
5387
5388 static dbus_bool_t
5389 array_set_value (TestTypeNode   *node,
5390                  DBusTypeReader *reader,
5391                  DBusTypeReader *realign_root,
5392                  int             seed)
5393 {
5394   return array_read_or_set_value (node, reader, realign_root, seed);
5395 }
5396
5397 static dbus_bool_t
5398 array_build_signature (TestTypeNode   *node,
5399                        DBusString     *str)
5400 {
5401   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5402   int orig_len;
5403
5404   orig_len = _dbus_string_get_length (str);
5405
5406   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
5407     goto oom;
5408
5409   if (!node_build_signature (_dbus_list_get_first (&container->children),
5410                              str))
5411     goto oom;
5412
5413   return TRUE;
5414
5415  oom:
5416   _dbus_string_set_length (str, orig_len);
5417   return FALSE;
5418 }
5419
5420  /* 10 is random just to add another seed that we use in the suite */
5421 #define VARIANT_SEED 10
5422
5423 static dbus_bool_t
5424 variant_write_value (TestTypeNode   *node,
5425                      DataBlock      *block,
5426                      DBusTypeWriter *writer,
5427                      int             seed)
5428 {
5429   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5430   DataBlockState saved;
5431   DBusTypeWriter sub;
5432   DBusString content_signature;
5433   TestTypeNode *child;
5434
5435   _dbus_assert (container->children != NULL);
5436   _dbus_assert (_dbus_list_length_is_one (&container->children));
5437
5438   child = _dbus_list_get_first (&container->children);
5439
5440   data_block_save (block, &saved);
5441
5442   if (!_dbus_string_init (&content_signature))
5443     return FALSE;
5444
5445   if (!node_build_signature (child,
5446                              &content_signature))
5447     goto oom;
5448
5449   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT,
5450                                   &content_signature, 0,
5451                                   &sub))
5452     goto oom;
5453
5454   if (!node_write_value (child, block, &sub, seed + VARIANT_SEED))
5455     goto oom;
5456
5457   if (!_dbus_type_writer_unrecurse (writer, &sub))
5458     goto oom;
5459
5460   _dbus_string_free (&content_signature);
5461   return TRUE;
5462
5463  oom:
5464   data_block_restore (block, &saved);
5465   _dbus_string_free (&content_signature);
5466   return FALSE;
5467 }
5468
5469 static dbus_bool_t
5470 variant_read_or_set_value (TestTypeNode   *node,
5471                            DBusTypeReader *reader,
5472                            DBusTypeReader *realign_root,
5473                            int             seed)
5474 {
5475   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5476   DBusTypeReader sub;
5477   TestTypeNode *child;
5478
5479   _dbus_assert (container->children != NULL);
5480   _dbus_assert (_dbus_list_length_is_one (&container->children));
5481
5482   child = _dbus_list_get_first (&container->children);
5483
5484   check_expected_type (reader, DBUS_TYPE_VARIANT);
5485
5486   _dbus_type_reader_recurse (reader, &sub);
5487
5488   if (realign_root == NULL)
5489     {
5490       if (!node_read_value (child, &sub, seed + VARIANT_SEED))
5491         return FALSE;
5492     }
5493   else
5494     {
5495       if (!node_set_value (child, &sub, realign_root, seed + VARIANT_SEED))
5496         return FALSE;
5497     }
5498
5499   NEXT_EXPECTING_FALSE (&sub);
5500
5501   return TRUE;
5502 }
5503
5504 static dbus_bool_t
5505 variant_read_value (TestTypeNode   *node,
5506                     DBusTypeReader *reader,
5507                     int             seed)
5508 {
5509   return variant_read_or_set_value (node, reader, NULL, seed);
5510 }
5511
5512 static dbus_bool_t
5513 variant_set_value (TestTypeNode   *node,
5514                    DBusTypeReader *reader,
5515                    DBusTypeReader *realign_root,
5516                    int             seed)
5517 {
5518   return variant_read_or_set_value (node, reader, realign_root, seed);
5519 }
5520
5521 static void
5522 container_destroy (TestTypeNode *node)
5523 {
5524   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
5525   DBusList *link;
5526
5527   link = _dbus_list_get_first_link (&container->children);
5528   while (link != NULL)
5529     {
5530       TestTypeNode *child = link->data;
5531       DBusList *next = _dbus_list_get_next_link (&container->children, link);
5532
5533       node_destroy (child);
5534
5535       _dbus_list_free_link (link);
5536
5537       link = next;
5538     }
5539 }
5540
5541 #endif /* DBUS_BUILD_TESTS */