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