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