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