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