add int64 to test suites, fix minor bug where marshaling assumed that DBusOctets8...
[platform/upstream/dbus.git] / dbus / dbus-marshal-recursive.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c  Marshalling routines for recursive types
3  *
4  * Copyright (C) 2004 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-marshal-recursive.h"
25 #include "dbus-internals.h"
26
27 /**
28  * @addtogroup DBusMarshal
29  * @{
30  */
31 #define RECURSIVE_MARSHAL_TRACE 0
32
33 struct DBusTypeReaderClass
34 {
35   const char *name;
36   dbus_bool_t types_only; /* only iterates over types, not values */
37   void        (* recurse)          (DBusTypeReader *sub,
38                                     DBusTypeReader *parent);
39   int         (* get_current_type) (DBusTypeReader *reader);
40   void        (* next)             (DBusTypeReader *reader,
41                                     int             current_type);
42 };
43
44 static int
45 first_type_in_signature (const DBusString *str,
46                          int               pos)
47 {
48   int t;
49
50   t = _dbus_string_get_byte (str, pos);
51
52   if (t == DBUS_STRUCT_BEGIN_CHAR)
53     return DBUS_TYPE_STRUCT;
54   else
55     return t;
56 }
57
58 static int
59 element_type_get_alignment (const DBusString *str,
60                             int               pos)
61 {
62   return _dbus_type_get_alignment (first_type_in_signature (str, pos));
63 }
64
65 static void
66 reader_init (DBusTypeReader    *reader,
67              int                byte_order,
68              const DBusString  *type_str,
69              int                type_pos,
70              const DBusString  *value_str,
71              int                value_pos)
72 {
73   reader->byte_order = byte_order;
74   reader->finished = FALSE;
75   reader->type_str = type_str;
76   reader->type_pos = type_pos;
77   reader->value_str = value_str;
78   reader->value_pos = value_pos;
79 }
80
81 static void
82 base_reader_recurse (DBusTypeReader *sub,
83                      DBusTypeReader *parent)
84 {
85   /* point subreader at the same place as parent */
86   reader_init (sub,
87                parent->byte_order,
88                parent->type_str,
89                parent->type_pos,
90                parent->value_str,
91                parent->value_pos);
92 }
93
94 static void
95 struct_types_only_reader_recurse (DBusTypeReader *sub,
96                                   DBusTypeReader *parent)
97 {
98   base_reader_recurse (sub, parent);
99
100   _dbus_assert (_dbus_string_get_byte (sub->type_str,
101                                        sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
102
103   sub->type_pos += 1;
104 }
105
106 static void
107 struct_reader_recurse (DBusTypeReader *sub,
108                        DBusTypeReader *parent)
109 {
110   struct_types_only_reader_recurse (sub, parent);
111
112   /* struct has 8 byte alignment */
113   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
114 }
115
116 static void
117 array_types_only_reader_recurse (DBusTypeReader *sub,
118                                  DBusTypeReader *parent)
119 {
120   base_reader_recurse (sub, parent);
121
122   /* point type_pos at the array element type */
123   sub->type_pos += 1;
124
125   sub->u.array.element_type = first_type_in_signature (sub->type_str,
126                                                        sub->type_pos);
127
128   /* Init with values likely to crash things if misused */
129   sub->u.array.start_pos = _DBUS_INT_MAX;
130   sub->u.array.len = _DBUS_INT_MAX;
131 }
132
133 static void
134 array_reader_recurse (DBusTypeReader *sub,
135                       DBusTypeReader *parent)
136 {
137   dbus_uint32_t array_len;
138   int alignment;
139
140   _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
141
142   array_types_only_reader_recurse (sub, parent);
143
144   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
145
146   _dbus_demarshal_basic_type (sub->value_str,
147                               DBUS_TYPE_UINT32,
148                               &array_len,
149                               sub->byte_order,
150                               &sub->value_pos);
151
152   sub->u.array.len = array_len;
153
154   alignment = element_type_get_alignment (sub->type_str,
155                                           sub->type_pos);
156
157   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
158
159   sub->u.array.start_pos = sub->value_pos;
160
161 #if RECURSIVE_MARSHAL_TRACE
162   _dbus_verbose ("    type reader %p array start = %d array len = %d array element type = %s\n",
163                  sub,
164                  sub->u.array.start_pos,
165                  sub->u.array.len,
166                  _dbus_type_to_string (sub->u.array.element_type));
167 #endif
168 }
169
170 static void
171 variant_reader_recurse (DBusTypeReader *sub,
172                         DBusTypeReader *parent)
173 {
174   int sig_len;
175
176   _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
177
178   base_reader_recurse (sub, parent);
179
180   /* Variant is 1 byte sig length (without nul), signature with nul,
181    * padding to 8-boundary, then values
182    */
183
184   sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
185
186   sub->type_str = sub->value_str;
187   sub->type_pos = sub->value_pos + 1;
188
189   sub->value_pos = sub->type_pos + sig_len + 1;
190
191   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
192
193 #if RECURSIVE_MARSHAL_TRACE
194   _dbus_verbose ("    type reader %p variant containing '%s'\n",
195                  sub,
196                  _dbus_string_get_const_data_len (sub->type_str,
197                                                   sub->type_pos, 0));
198 #endif
199 }
200
201 static int
202 base_reader_get_current_type (DBusTypeReader *reader)
203 {
204   int t;
205
206   t = first_type_in_signature (reader->type_str,
207                                reader->type_pos);
208
209   return t;
210 }
211
212 static int
213 struct_reader_get_current_type (DBusTypeReader *reader)
214 {
215   int t;
216
217   if (reader->finished)
218     t = DBUS_TYPE_INVALID;
219   else
220     t = first_type_in_signature (reader->type_str,
221                                  reader->type_pos);
222
223   return t;
224 }
225
226 static int
227 array_types_only_reader_get_current_type (DBusTypeReader *reader)
228 {
229   int t;
230
231   if (reader->finished)
232     t = DBUS_TYPE_INVALID;
233   else
234     t = reader->u.array.element_type;
235
236   return t;
237 }
238
239 static int
240 array_reader_get_current_type (DBusTypeReader *reader)
241 {
242   int t;
243   int end_pos;
244
245   /* return the array element type if elements remain, and
246    * TYPE_INVALID otherwise
247    */
248
249   end_pos = reader->u.array.start_pos + reader->u.array.len;
250
251   _dbus_assert (reader->value_pos <= end_pos);
252   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
253
254   if (reader->value_pos < end_pos)
255     t = reader->u.array.element_type;
256   else
257     t = DBUS_TYPE_INVALID;
258
259   return t;
260 }
261
262 static void
263 skip_one_complete_type (const DBusString *type_str,
264                         int              *type_pos)
265 {
266   while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
267     *type_pos += 1;
268
269   if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
270     {
271       int depth;
272       depth = 1;
273       *type_pos += 1;
274       while (depth > 0)
275         {
276           switch (_dbus_string_get_byte (type_str, *type_pos))
277             {
278             case DBUS_STRUCT_BEGIN_CHAR:
279               depth += 1;
280               break;
281             case DBUS_STRUCT_END_CHAR:
282               depth -= 1;
283               break;
284             case DBUS_TYPE_INVALID:
285               _dbus_assert_not_reached ("unbalanced parens in signature");
286               break;
287             }
288           *type_pos += 1;
289         }
290     }
291   else
292     *type_pos += 1;
293 }
294
295 static void
296 skip_array_values (int               element_type,
297                    const DBusString *value_str,
298                    int              *value_pos,
299                    int               byte_order)
300 {
301   dbus_uint32_t array_len;
302   int pos;
303   int alignment;
304
305   pos = _DBUS_ALIGN_VALUE (*value_pos, 4);
306
307   _dbus_demarshal_basic_type (value_str,
308                               DBUS_TYPE_UINT32,
309                               &array_len,
310                               byte_order,
311                               &pos);
312
313   alignment = _dbus_type_get_alignment (element_type);
314
315   pos = _DBUS_ALIGN_VALUE (pos, alignment);
316
317   *value_pos = pos + array_len;
318 }
319
320 static void
321 base_reader_next (DBusTypeReader *reader,
322                   int             current_type)
323 {
324   switch (current_type)
325     {
326     case DBUS_TYPE_STRUCT:
327       /* Scan forward over the entire container contents */
328       {
329         DBusTypeReader sub;
330
331         /* Recurse into the struct */
332         _dbus_type_reader_recurse (reader, &sub);
333
334         /* Skip everything in this subreader */
335         while (_dbus_type_reader_next (&sub))
336           {
337             /* nothing */;
338           }
339
340         /* Now we are at the end of this container */
341         reader->type_pos = sub.type_pos;
342
343         if (!reader->klass->types_only)
344           reader->value_pos = sub.value_pos;
345       }
346       break;
347
348     case DBUS_TYPE_ARRAY:
349       {
350         if (!reader->klass->types_only)
351           skip_array_values (first_type_in_signature (reader->type_str,
352                                                       reader->type_pos + 1),
353                              reader->value_str, &reader->value_pos, reader->byte_order);
354
355         skip_one_complete_type (reader->type_str, &reader->type_pos);
356       }
357       break;
358
359     default:
360       if (!reader->klass->types_only)
361         _dbus_marshal_skip_basic_type (reader->value_str,
362                                        current_type, reader->byte_order,
363                                        &reader->value_pos);
364
365       reader->type_pos += 1;
366       break;
367     }
368 }
369
370 static void
371 struct_reader_next (DBusTypeReader *reader,
372                     int             current_type)
373 {
374   int t;
375
376   base_reader_next (reader, current_type);
377
378   /* for STRUCT containers we return FALSE at the end of the struct,
379    * for INVALID we return FALSE at the end of the signature.
380    * In both cases we arrange for get_current_type() to return INVALID
381    * which is defined to happen iff we're at the end (no more next())
382    */
383   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
384   if (t == DBUS_STRUCT_END_CHAR)
385     {
386       reader->type_pos += 1;
387       reader->finished = TRUE;
388     }
389 }
390
391 static void
392 array_types_only_reader_next (DBusTypeReader *reader,
393                               int             current_type)
394 {
395   /* We have one "element" to be iterated over
396    * in each array, which is its element type.
397    * So the finished flag indicates whether we've
398    * iterated over it yet or not.
399    */
400   reader->finished = TRUE;
401 }
402
403 static void
404 array_reader_next (DBusTypeReader *reader,
405                    int             current_type)
406 {
407   /* Skip one array element */
408   int end_pos;
409
410   end_pos = reader->u.array.start_pos + reader->u.array.len;
411
412   _dbus_assert (reader->value_pos < end_pos);
413   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
414
415   if (reader->u.array.element_type == DBUS_TYPE_STRUCT)
416     {
417       DBusTypeReader sub;
418
419       /* Recurse into the struct */
420       _dbus_type_reader_recurse (reader, &sub);
421
422       /* Skip everything in this element */
423       while (_dbus_type_reader_next (&sub))
424         {
425           /* nothing */;
426         }
427
428       /* Now we are at the end of this element */
429       reader->value_pos = sub.value_pos;
430     }
431   else if (reader->u.array.element_type == DBUS_TYPE_ARRAY)
432     {
433       skip_array_values (first_type_in_signature (reader->type_str,
434                                                   reader->type_pos + 1),
435                          reader->value_str, &reader->value_pos, reader->byte_order);
436     }
437   else
438     {
439       _dbus_marshal_skip_basic_type (reader->value_str,
440                                      current_type, reader->byte_order,
441                                      &reader->value_pos);
442     }
443
444   _dbus_assert (reader->value_pos <= end_pos);
445
446   if (reader->value_pos == end_pos)
447     {
448       skip_one_complete_type (reader->type_str,
449                               &reader->type_pos);
450     }
451 }
452
453 static const DBusTypeReaderClass body_reader_class = {
454   "body",
455   FALSE,
456   NULL, /* body is always toplevel, so doesn't get recursed into */
457   base_reader_get_current_type,
458   base_reader_next
459 };
460
461 static const DBusTypeReaderClass body_types_only_reader_class = {
462   "body types",
463   TRUE,
464   NULL, /* body is always toplevel, so doesn't get recursed into */
465   base_reader_get_current_type,
466   base_reader_next
467 };
468
469 static const DBusTypeReaderClass struct_reader_class = {
470   "struct",
471   FALSE,
472   struct_reader_recurse,
473   struct_reader_get_current_type,
474   struct_reader_next
475 };
476
477 static const DBusTypeReaderClass struct_types_only_reader_class = {
478   "struct types",
479   TRUE,
480   struct_types_only_reader_recurse,
481   struct_reader_get_current_type,
482   struct_reader_next
483 };
484
485 static const DBusTypeReaderClass array_reader_class = {
486   "array",
487   FALSE,
488   array_reader_recurse,
489   array_reader_get_current_type,
490   array_reader_next
491 };
492
493 static const DBusTypeReaderClass array_types_only_reader_class = {
494   "array types",
495   TRUE,
496   array_types_only_reader_recurse,
497   array_types_only_reader_get_current_type,
498   array_types_only_reader_next
499 };
500
501 static const DBusTypeReaderClass variant_reader_class = {
502   "variant",
503   FALSE,
504   variant_reader_recurse,
505   base_reader_get_current_type,
506   base_reader_next
507 };
508
509 void
510 _dbus_type_reader_init (DBusTypeReader    *reader,
511                         int                byte_order,
512                         const DBusString  *type_str,
513                         int                type_pos,
514                         const DBusString  *value_str,
515                         int                value_pos)
516 {
517   reader->klass = &body_reader_class;
518
519   reader_init (reader, byte_order, type_str, type_pos,
520                value_str, value_pos);
521
522 #if RECURSIVE_MARSHAL_TRACE
523   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
524                  reader, reader->type_pos, reader->value_pos,
525                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
526 #endif
527 }
528
529 void
530 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
531                                    const DBusString  *type_str,
532                                    int                type_pos)
533 {
534   reader->klass = &body_types_only_reader_class;
535
536   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
537                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
538
539 #if RECURSIVE_MARSHAL_TRACE
540   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
541                  reader, reader->type_pos,
542                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
543 #endif
544 }
545
546 int
547 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
548 {
549   int t;
550
551   t = (* reader->klass->get_current_type) (reader);
552
553   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
554   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
555
556 #if 0
557   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
558                  reader, reader->type_pos,
559                  _dbus_type_to_string (t));
560 #endif
561
562   return t;
563 }
564
565 dbus_bool_t
566 _dbus_type_reader_array_is_empty (DBusTypeReader *reader)
567 {
568   dbus_uint32_t array_len;
569   int len_pos;
570
571   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
572   _dbus_assert (!reader->klass->types_only);
573
574   len_pos = _DBUS_ALIGN_VALUE (reader->value_pos, 4);
575
576   _dbus_demarshal_basic_type (reader->value_str,
577                               DBUS_TYPE_UINT32,
578                               &array_len,
579                               reader->byte_order,
580                               &len_pos);
581
582   return array_len == 0;
583 }
584
585 void
586 _dbus_type_reader_read_basic (DBusTypeReader    *reader,
587                               void              *value)
588 {
589   int t;
590   int next;
591
592   _dbus_assert (!reader->klass->types_only);
593
594   t = _dbus_type_reader_get_current_type (reader);
595
596   next = reader->value_pos;
597   _dbus_demarshal_basic_type (reader->value_str,
598                               t, value,
599                               reader->byte_order,
600                               &next);
601
602
603 #if RECURSIVE_MARSHAL_TRACE
604   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
605                  reader, reader->type_pos, reader->value_pos, next,
606                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
607 #endif
608 }
609
610 dbus_bool_t
611 _dbus_type_reader_read_array_of_basic (DBusTypeReader    *reader,
612                                        int                type,
613                                        void             **array,
614                                        int               *array_len)
615 {
616   _dbus_assert (!reader->klass->types_only);
617
618 }
619
620 /**
621  * Initialize a new reader pointing to the first type and
622  * corresponding value that's a child of the current container. It's
623  * an error to call this if the current type is a non-container.
624  *
625  * Note that DBusTypeReader traverses values, not types. So if you
626  * have an empty array of array of int, you can't recurse into it. You
627  * can only recurse into each element.
628  *
629  * @param reader the reader
630  * @param sub a reader to init pointing to the first child
631  */
632 void
633 _dbus_type_reader_recurse (DBusTypeReader *reader,
634                            DBusTypeReader *sub)
635 {
636   int t;
637
638   t = first_type_in_signature (reader->type_str, reader->type_pos);
639
640   switch (t)
641     {
642     case DBUS_TYPE_STRUCT:
643       if (reader->klass->types_only)
644         sub->klass = &struct_types_only_reader_class;
645       else
646         sub->klass = &struct_reader_class;
647       break;
648     case DBUS_TYPE_ARRAY:
649       if (reader->klass->types_only)
650         sub->klass = &array_types_only_reader_class;
651       else
652         sub->klass = &array_reader_class;
653       break;
654     case DBUS_TYPE_VARIANT:
655       if (reader->klass->types_only)
656         _dbus_assert_not_reached ("can't recurse into variant typecode");
657       else
658         sub->klass = &variant_reader_class;
659       break;
660     default:
661       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
662 #ifndef DBUS_DISABLE_CHECKS
663       if (t == DBUS_TYPE_INVALID)
664         _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
665 #endif /* DBUS_DISABLE_CHECKS */
666
667       _dbus_assert_not_reached ("don't yet handle recursing into this type");
668     }
669
670   (* sub->klass->recurse) (sub, reader);
671
672 #if RECURSIVE_MARSHAL_TRACE
673   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
674                  sub, sub->type_pos, sub->value_pos,
675                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
676 #endif
677 }
678
679 /**
680  * Skip to the next value on this "level". e.g. the next field in a
681  * struct, the next value in an array, the next key or value in a
682  * dict. Returns FALSE at the end of the current container.
683  *
684  * @param reader the reader
685  * @returns FALSE if nothing more to read at or below this level
686  */
687 dbus_bool_t
688 _dbus_type_reader_next (DBusTypeReader *reader)
689 {
690   int t;
691
692   t = _dbus_type_reader_get_current_type (reader);
693
694 #if RECURSIVE_MARSHAL_TRACE
695   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
696                  reader, reader->type_pos, reader->value_pos,
697                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
698                  _dbus_type_to_string (t));
699 #endif
700
701   if (t == DBUS_TYPE_INVALID)
702     return FALSE;
703
704   (* reader->klass->next) (reader, t);
705
706 #if RECURSIVE_MARSHAL_TRACE
707   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
708                  reader, reader->type_pos, reader->value_pos,
709                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
710                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
711 #endif
712
713   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
714 }
715
716
717 /*
718  *
719  *
720  *         DBusTypeWriter
721  *
722  *
723  *
724  */
725
726 void
727 _dbus_type_writer_init (DBusTypeWriter *writer,
728                         int             byte_order,
729                         DBusString     *type_str,
730                         int             type_pos,
731                         DBusString     *value_str,
732                         int             value_pos)
733 {
734   writer->byte_order = byte_order;
735   writer->type_str = type_str;
736   writer->type_pos = type_pos;
737   writer->value_str = value_str;
738   writer->value_pos = value_pos;
739   writer->container_type = DBUS_TYPE_INVALID;
740   writer->type_pos_is_expectation = FALSE;
741
742 #if RECURSIVE_MARSHAL_TRACE
743   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
744                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
745 #endif
746 }
747
748 static dbus_bool_t
749 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
750                                            int             type,
751                                            const void     *value)
752 {
753   int old_value_len;
754   int bytes_written;
755
756   old_value_len = _dbus_string_get_length (writer->value_str);
757
758   if (!_dbus_marshal_basic_type (writer->value_str,
759                                  writer->value_pos,
760                                  type,
761                                  value,
762                                  writer->byte_order))
763     return FALSE;
764
765   bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
766
767   writer->value_pos += bytes_written;
768
769   return TRUE;
770 }
771
772 /* If our parent is an array, things are a little bit complicated.
773  *
774  * The parent must have a complete element type, such as
775  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
776  * unclosed parens, or an "a" with no following type.
777  *
778  * To recurse, the only allowed operation is to recurse into the
779  * first type in the element type. So for "i" you can't recurse, for
780  * "ai" you can recurse into the array, for "(ii)" you can recurse
781  * into the struct.
782  *
783  * If you recurse into the array for "ai", then you must specify
784  * "i" for the element type of the array you recurse into.
785  *
786  * While inside an array at any level, we need to avoid writing to
787  * type_str, since the type only appears once for the whole array,
788  * it does not appear for each array element.
789  *
790  * While inside an array type_pos points to the expected next
791  * typecode, rather than the next place we could write a typecode.
792  */
793 static void
794 writer_recurse_init_and_check (DBusTypeWriter *writer,
795                                int             container_type,
796                                DBusTypeWriter *sub)
797 {
798   _dbus_type_writer_init (sub,
799                           writer->byte_order,
800                           writer->type_str,
801                           writer->type_pos,
802                           writer->value_str,
803                           writer->value_pos);
804
805   sub->container_type = container_type;
806
807   if (writer->type_pos_is_expectation ||
808       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
809     sub->type_pos_is_expectation = TRUE;
810   else
811     sub->type_pos_is_expectation = FALSE;
812
813 #ifndef DBUS_DISABLE_CHECKS
814   if (writer->type_pos_is_expectation)
815     {
816       int expected;
817
818       expected = first_type_in_signature (writer->type_str, writer->type_pos);
819
820       if (expected != sub->container_type)
821         {
822           _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
823                       _dbus_type_to_string (sub->container_type),
824                       _dbus_type_to_string (expected));
825           _dbus_assert_not_reached ("bad array element or variant content written");
826         }
827     }
828 #endif /* DBUS_DISABLE_CHECKS */
829
830 #if RECURSIVE_MARSHAL_TRACE
831   _dbus_verbose ("  type writer %p recurse parent type_pos = %d value_pos = %d is_expectation = %d container_type = %s remaining sig '%s'\n",
832                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
833                  _dbus_type_to_string (writer->container_type),
834                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
835   _dbus_verbose ("  type writer %p recurse sub    type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
836                  sub, sub->type_pos, sub->value_pos,
837                  sub->type_pos_is_expectation,
838                  _dbus_type_to_string (sub->container_type));
839 #endif
840 }
841
842 static dbus_bool_t
843 write_or_verify_typecode (DBusTypeWriter *writer,
844                           int             typecode)
845 {
846   /* A subwriter inside an array or variant will have type_pos
847    * pointing to the expected typecode; a writer not inside an array
848    * or variant has type_pos pointing to the next place to insert a
849    * typecode.
850    */
851 #if RECURSIVE_MARSHAL_TRACE
852   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
853                  writer, writer->type_pos,
854                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
855 #endif
856
857   if (writer->type_pos_is_expectation)
858     {
859 #ifndef DBUS_DISABLE_CHECKS
860       {
861         int expected;
862
863         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
864
865         if (expected != typecode)
866           {
867             _dbus_warn ("Array or Variant type requires that type %s be written, but %s was written\n",
868                         _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
869             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
870           }
871       }
872 #endif /* DBUS_DISABLE_CHECKS */
873
874       /* if immediately inside an array we'd always be appending an element,
875        * so the expected type doesn't change; if inside a struct or something
876        * below an array, we need to move through said struct or something.
877        */
878       if (writer->container_type != DBUS_TYPE_ARRAY)
879         writer->type_pos += 1;
880     }
881   else
882     {
883       if (!_dbus_string_insert_byte (writer->type_str,
884                                      writer->type_pos,
885                                      typecode))
886         return FALSE;
887
888       writer->type_pos += 1;
889     }
890
891 #if RECURSIVE_MARSHAL_TRACE
892   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
893                  writer, writer->type_pos,
894                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
895 #endif
896
897   return TRUE;
898 }
899
900 dbus_bool_t
901 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
902                                   DBusTypeWriter *sub)
903 {
904   writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
905
906   /* Ensure that we'll be able to add alignment padding and the typecode */
907   if (!_dbus_string_alloc_space (sub->value_str, 8))
908     return FALSE;
909
910   if (!_dbus_string_alloc_space (sub->type_str, 1))
911     return FALSE;
912
913   if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
914     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
915
916   if (!_dbus_string_insert_bytes (sub->value_str,
917                                   sub->value_pos,
918                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
919                                   '\0'))
920     _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
921   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
922
923   return TRUE;
924 }
925
926 dbus_bool_t
927 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
928                                  const char     *element_type,
929                                  DBusTypeWriter *sub)
930 {
931   int element_type_len;
932   DBusString element_type_str;
933   dbus_uint32_t value = 0;
934   int alignment;
935   int aligned;
936   DBusString str;
937
938   writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
939
940   _dbus_string_init_const (&element_type_str, element_type);
941   element_type_len = _dbus_string_get_length (&element_type_str);
942
943 #ifndef DBUS_DISABLE_CHECKS
944   if (writer->container_type == DBUS_TYPE_ARRAY)
945     {
946       if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
947                                          writer->type_str, writer->u.array.element_type_pos + 1))
948         {
949           _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
950                       element_type);
951           _dbus_assert_not_reached ("incompatible type for child array");
952         }
953     }
954 #endif /* DBUS_DISABLE_CHECKS */
955
956   /* 4 bytes for the array length and 4 bytes possible padding */
957   if (!_dbus_string_alloc_space (sub->value_str, 8))
958     return FALSE;
959
960   sub->type_pos += 1; /* move to point to the element type, since type_pos
961                        * should be the expected type for further writes
962                        */
963   sub->u.array.element_type_pos = sub->type_pos;
964
965   if (!writer->type_pos_is_expectation)
966     {
967       /* sub is a toplevel/outermost array so we need to write the type data */
968
969       /* alloc space for array typecode, element signature, possible 7
970        * bytes of padding
971        */
972       if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
973         return FALSE;
974
975       if (!_dbus_string_insert_byte (writer->type_str,
976                                      writer->type_pos,
977                                      DBUS_TYPE_ARRAY))
978         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
979
980       if (!_dbus_string_copy (&element_type_str, 0,
981                               sub->type_str, sub->u.array.element_type_pos))
982         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
983     }
984
985   /* If the parent is an array, we hold type_pos pointing at the array element type;
986    * otherwise advance it to reflect the array value we just recursed into
987    */
988   if (writer->container_type != DBUS_TYPE_ARRAY)
989     writer->type_pos += 1 + element_type_len;
990   else
991     _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
992
993   /* Write the length */
994   sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
995
996   if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
997                                                   &value))
998     _dbus_assert_not_reached ("should not have failed to insert array len");
999
1000   _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1001
1002   /* Write alignment padding for array elements */
1003   _dbus_string_init_const (&str, element_type);
1004   alignment = element_type_get_alignment (&str, 0);
1005
1006   aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1007   if (aligned != sub->value_pos)
1008     {
1009       if (!_dbus_string_insert_bytes (sub->value_str,
1010                                       sub->value_pos,
1011                                       aligned - sub->value_pos,
1012                                       '\0'))
1013         _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1014
1015       sub->value_pos = aligned;
1016     }
1017   sub->u.array.start_pos = sub->value_pos;
1018
1019   _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1020   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1021
1022 #if RECURSIVE_MARSHAL_TRACE
1023   _dbus_verbose ("  type writer %p recurse array done remaining sig '%s'\n", sub,
1024                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
1025 #endif
1026
1027   return TRUE;
1028 }
1029
1030 /* Variant value will normally have:
1031  *   1 byte signature length not including nul
1032  *   signature typecodes (nul terminated)
1033  *   padding to 8-boundary
1034  *   body according to signature
1035  *
1036  * The signature string can only have a single type
1037  * in it but that type may be complex/recursive.
1038  *
1039  * So a typical variant type with the integer 3 will have these
1040  * octets:
1041  *   0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1042  *
1043  * For an array of 4-byte types stuffed into variants, the padding to
1044  * 8-boundary is only the 1 byte that is required for the 4-boundary
1045  * anyhow for all array elements after the first one. And for single
1046  * variants in isolation, wasting a few bytes is hardly a big deal.
1047  *
1048  * The main world of hurt for writing out a variant is that the type
1049  * string is the same string as the value string. Which means
1050  * inserting to the type string will move the value_pos; and it means
1051  * that inserting to the type string could break type alignment.
1052  *
1053  * This type alignment issue is why the body of the variant is always
1054  * 8-aligned. Then we know that re-8-aligning the start of the body
1055  * will always correctly align the full contents of the variant type.
1056  */
1057 dbus_bool_t
1058 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1059                                    const char     *contained_type,
1060                                    DBusTypeWriter *sub)
1061 {
1062   int contained_type_len;
1063   DBusString contained_type_str;
1064
1065   writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1066
1067   _dbus_string_init_const (&contained_type_str, contained_type);
1068
1069   contained_type_len = _dbus_string_get_length (&contained_type_str);
1070
1071   /* Allocate space for the worst case, which is 1 byte sig
1072    * length, nul byte at end of sig, and 7 bytes padding to
1073    * 8-boundary.
1074    */
1075   if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1076     return FALSE;
1077
1078   /* write VARIANT typecode to the parent's type string */
1079   if (!write_or_verify_typecode (sub, DBUS_TYPE_VARIANT))
1080     return FALSE;
1081
1082   if (!_dbus_string_insert_byte (sub->value_str,
1083                                  sub->value_pos,
1084                                  contained_type_len))
1085     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1086
1087   sub->value_pos += 1;
1088
1089   /* Here we switch over to the expected type sig we're about to write */
1090   sub->type_str = sub->value_str;
1091   sub->type_pos = sub->value_pos;
1092
1093   if (!_dbus_string_copy (&contained_type_str, 0,
1094                           sub->value_str, sub->value_pos))
1095     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1096
1097   sub->value_pos += contained_type_len;
1098
1099   if (!_dbus_string_insert_byte (sub->value_str,
1100                                  sub->value_pos,
1101                                  DBUS_TYPE_INVALID))
1102     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1103
1104   sub->value_pos += 1;
1105
1106   if (!_dbus_string_insert_bytes (sub->value_str,
1107                                   sub->value_pos,
1108                                   _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1109                                   '\0'))
1110     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1111   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1112
1113   return TRUE;
1114 }
1115
1116 dbus_bool_t
1117 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1118                              DBusTypeWriter *sub)
1119 {
1120   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1121
1122   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1123   _dbus_assert (!writer->type_pos_is_expectation ||
1124                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1125
1126 #if RECURSIVE_MARSHAL_TRACE
1127   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1128                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1129                  _dbus_type_to_string (writer->container_type));
1130   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1131                  sub, sub->type_pos, sub->value_pos,
1132                  sub->type_pos_is_expectation,
1133                  _dbus_type_to_string (sub->container_type));
1134 #endif
1135
1136   if (sub->container_type == DBUS_TYPE_STRUCT)
1137     {
1138       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1139         return FALSE;
1140     }
1141   else if (sub->container_type == DBUS_TYPE_ARRAY)
1142     {
1143       dbus_uint32_t len;
1144
1145       /* Set the array length */
1146       len = sub->value_pos - sub->u.array.start_pos;
1147       _dbus_marshal_set_uint32 (sub->value_str,
1148                                 sub->byte_order,
1149                                 sub->u.array.len_pos,
1150                                 len);
1151 #if RECURSIVE_MARSHAL_TRACE
1152       _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
1153                      len, sub->u.array.len_pos);
1154 #endif
1155     }
1156
1157   /* Now get type_pos right for the parent writer. Here are the cases:
1158    *
1159    * Cases !writer->type_pos_is_expectation:
1160    *   (in these cases we want to update to the new insertion point)
1161    *
1162    * - if we recursed into a STRUCT then we didn't know in advance
1163    *   what the types in the struct would be; so we have to fill in
1164    *   that information now.
1165    *       writer->type_pos = sub->type_pos
1166    *
1167    * - if we recursed into anything else, we knew the full array
1168    *   type, or knew the single typecode marking VARIANT, so
1169    *   writer->type_pos is already correct.
1170    *       writer->type_pos should remain as-is
1171    *
1172    * - note that the parent is never an ARRAY or VARIANT, if it were
1173    *   then type_pos_is_expectation would be TRUE. The parent
1174    *   is thus known to be a toplevel or STRUCT.
1175    *
1176    * Cases where writer->type_pos_is_expectation:
1177    *   (in these cases we want to update to next expected type to write)
1178    *
1179    * - we recursed from STRUCT into STRUCT and we didn't increment
1180    *   type_pos in the parent just to stay consistent with the
1181    *   !writer->type_pos_is_expectation case (though we could
1182    *   special-case this in recurse_struct instead if we wanted)
1183    *       writer->type_pos = sub->type_pos
1184    *
1185    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1186    *   for parent should have been incremented already
1187    *       writer->type_pos should remain as-is
1188    *
1189    * - we recursed from ARRAY into a sub-element, so type_pos in the
1190    *   parent is the element type and should remain the element type
1191    *   for the benefit of the next child element
1192    *       writer->type_pos should remain as-is
1193    *
1194    * - we recursed from VARIANT into its value, so type_pos in the
1195    *   parent makes no difference since there's only one value
1196    *   and we just finished writing it and won't use type_pos again
1197    *       writer->type_pos should remain as-is
1198    */
1199   if (sub->container_type == DBUS_TYPE_STRUCT &&
1200       (writer->container_type == DBUS_TYPE_STRUCT ||
1201        writer->container_type == DBUS_TYPE_INVALID))
1202     {
1203       /* Advance the parent to the next struct field */
1204       writer->type_pos = sub->type_pos;
1205     }
1206
1207   writer->value_pos = sub->value_pos;
1208
1209 #if RECURSIVE_MARSHAL_TRACE
1210   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1211                  writer, writer->type_pos, writer->value_pos,
1212                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1213 #endif
1214
1215   return TRUE;
1216 }
1217
1218 dbus_bool_t
1219 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1220                                int             type,
1221                                const void     *value)
1222 {
1223   dbus_bool_t retval;
1224
1225   /* First ensure that our type realloc will succeed */
1226   if (!_dbus_string_alloc_space (writer->type_str, 1))
1227     return FALSE;
1228
1229   retval = FALSE;
1230
1231   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1232     goto out;
1233
1234   if (!write_or_verify_typecode (writer, type))
1235     _dbus_assert_not_reached ("failed to write typecode after prealloc");
1236
1237   retval = TRUE;
1238
1239  out:
1240 #if RECURSIVE_MARSHAL_TRACE
1241   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1242                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1243 #endif
1244
1245   return retval;
1246 }
1247
1248 dbus_bool_t
1249 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1250                                int             type,
1251                                const void     *array,
1252                                int             array_len)
1253 {
1254
1255
1256 }
1257
1258 /** @} */ /* end of DBusMarshal group */
1259
1260 #ifdef DBUS_BUILD_TESTS
1261 #include "dbus-test.h"
1262 #include "dbus-list.h"
1263 #include <stdio.h>
1264 #include <stdlib.h>
1265
1266 typedef struct
1267 {
1268   DBusString signature;
1269   DBusString body;
1270 } DataBlock;
1271
1272 typedef struct
1273 {
1274   int saved_sig_len;
1275   int saved_body_len;
1276 } DataBlockState;
1277
1278 static dbus_bool_t
1279 data_block_init (DataBlock *block)
1280 {
1281   if (!_dbus_string_init (&block->signature))
1282     return FALSE;
1283
1284   if (!_dbus_string_init (&block->body))
1285     {
1286       _dbus_string_free (&block->signature);
1287       return FALSE;
1288     }
1289
1290   return TRUE;
1291 }
1292
1293 static void
1294 data_block_free (DataBlock *block)
1295 {
1296   _dbus_string_free (&block->signature);
1297   _dbus_string_free (&block->body);
1298 }
1299
1300 static void
1301 data_block_save (DataBlock      *block,
1302                  DataBlockState *state)
1303 {
1304   state->saved_sig_len = _dbus_string_get_length (&block->signature);
1305   state->saved_body_len = _dbus_string_get_length (&block->body);
1306 }
1307
1308 static void
1309 data_block_restore (DataBlock      *block,
1310                     DataBlockState *state)
1311 {
1312   /* These set_length should be shortening things so should always work */
1313
1314   if (!_dbus_string_set_length (&block->signature,
1315                                 state->saved_sig_len))
1316     _dbus_assert_not_reached ("could not restore signature length");
1317
1318   if (!_dbus_string_set_length (&block->body,
1319                                 state->saved_body_len))
1320     _dbus_assert_not_reached ("could not restore body length");
1321 }
1322
1323 static void
1324 data_block_init_reader_writer (DataBlock      *block,
1325                                int             byte_order,
1326                                DBusTypeReader *reader,
1327                                DBusTypeWriter *writer)
1328 {
1329   _dbus_type_reader_init (reader,
1330                           byte_order,
1331                           &block->signature,
1332                           _dbus_string_get_length (&block->signature),
1333                           &block->body,
1334                           _dbus_string_get_length (&block->body));
1335
1336   _dbus_type_writer_init (writer,
1337                           byte_order,
1338                           &block->signature,
1339                           _dbus_string_get_length (&block->signature),
1340                           &block->body,
1341                           _dbus_string_get_length (&block->body));
1342 }
1343
1344 static void
1345 real_check_expected_type (DBusTypeReader *reader,
1346                           int             expected,
1347                           const char     *funcname,
1348                           int             line)
1349 {
1350   int t;
1351
1352   t = _dbus_type_reader_get_current_type (reader);
1353
1354   if (t != expected)
1355     {
1356       _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1357                   _dbus_type_to_string (t),
1358                   _dbus_type_to_string (expected),
1359                   funcname, line);
1360
1361       exit (1);
1362     }
1363 }
1364
1365 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1366
1367 #define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \
1368  {                                                                                      \
1369     _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \
1370                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1371     _dbus_assert_not_reached ("test failed");                                           \
1372  }                                                                                      \
1373 } while (0)
1374
1375 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \
1376  {                                                                                      \
1377     _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \
1378                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1379     _dbus_assert_not_reached ("test failed");                                           \
1380  }                                                                                      \
1381  check_expected_type (reader, DBUS_TYPE_INVALID);                                       \
1382 } while (0)
1383
1384 #define SAMPLE_INT32           12345678
1385 #define SAMPLE_INT32_ALTERNATE 53781429
1386
1387 typedef struct TestTypeNode               TestTypeNode;
1388 typedef struct TestTypeNodeClass          TestTypeNodeClass;
1389 typedef struct TestTypeNodeContainer      TestTypeNodeContainer;
1390 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1391
1392 struct TestTypeNode
1393 {
1394   const TestTypeNodeClass *klass;
1395 };
1396
1397 struct TestTypeNodeContainer
1398 {
1399   TestTypeNode base;
1400   DBusList    *children;
1401 };
1402
1403 struct TestTypeNodeClass
1404 {
1405   int typecode;
1406
1407   int instance_size;
1408
1409   dbus_bool_t   (* construct)     (TestTypeNode   *node);
1410   void          (* destroy)       (TestTypeNode   *node);
1411
1412   dbus_bool_t (* write_value)     (TestTypeNode   *node,
1413                                    DataBlock      *block,
1414                                    DBusTypeWriter *writer,
1415                                    int             seed);
1416   dbus_bool_t (* read_value)      (TestTypeNode   *node,
1417                                    DataBlock      *block,
1418                                    DBusTypeReader *reader,
1419                                    int             seed);
1420   dbus_bool_t (* build_signature) (TestTypeNode   *node,
1421                                    DBusString     *str);
1422 };
1423
1424 struct TestTypeNodeContainerClass
1425 {
1426   TestTypeNodeClass base;
1427 };
1428
1429 static dbus_bool_t int32_write_value        (TestTypeNode   *node,
1430                                              DataBlock      *block,
1431                                              DBusTypeWriter *writer,
1432                                              int             seed);
1433 static dbus_bool_t int32_read_value         (TestTypeNode   *node,
1434                                              DataBlock      *block,
1435                                              DBusTypeReader *reader,
1436                                              int             seed);
1437 static dbus_bool_t int64_write_value        (TestTypeNode   *node,
1438                                              DataBlock      *block,
1439                                              DBusTypeWriter *writer,
1440                                              int             seed);
1441 static dbus_bool_t int64_read_value         (TestTypeNode   *node,
1442                                              DataBlock      *block,
1443                                              DBusTypeReader *reader,
1444                                              int             seed);
1445 static dbus_bool_t struct_1_write_value     (TestTypeNode   *node,
1446                                              DataBlock      *block,
1447                                              DBusTypeWriter *writer,
1448                                              int             seed);
1449 static dbus_bool_t struct_1_read_value      (TestTypeNode   *node,
1450                                              DataBlock      *block,
1451                                              DBusTypeReader *reader,
1452                                              int             seed);
1453 static dbus_bool_t struct_1_build_signature (TestTypeNode   *node,
1454                                              DBusString     *str);
1455 static dbus_bool_t struct_2_write_value     (TestTypeNode   *node,
1456                                              DataBlock      *block,
1457                                              DBusTypeWriter *writer,
1458                                              int             seed);
1459 static dbus_bool_t struct_2_read_value      (TestTypeNode   *node,
1460                                              DataBlock      *block,
1461                                              DBusTypeReader *reader,
1462                                              int             seed);
1463 static dbus_bool_t struct_2_build_signature (TestTypeNode   *node,
1464                                              DBusString     *str);
1465 static dbus_bool_t array_build_signature    (TestTypeNode   *node,
1466                                              DBusString     *str);
1467 static dbus_bool_t array_1_write_value      (TestTypeNode   *node,
1468                                              DataBlock      *block,
1469                                              DBusTypeWriter *writer,
1470                                              int             seed);
1471 static dbus_bool_t array_1_read_value       (TestTypeNode   *node,
1472                                              DataBlock      *block,
1473                                              DBusTypeReader *reader,
1474                                              int             seed);
1475 static dbus_bool_t array_0_write_value      (TestTypeNode   *node,
1476                                              DataBlock      *block,
1477                                              DBusTypeWriter *writer,
1478                                              int             seed);
1479 static dbus_bool_t array_0_read_value       (TestTypeNode   *node,
1480                                              DataBlock      *block,
1481                                              DBusTypeReader *reader,
1482                                              int             seed);
1483 static dbus_bool_t array_2_write_value      (TestTypeNode   *node,
1484                                              DataBlock      *block,
1485                                              DBusTypeWriter *writer,
1486                                              int             seed);
1487 static dbus_bool_t array_2_read_value       (TestTypeNode   *node,
1488                                              DataBlock      *block,
1489                                              DBusTypeReader *reader,
1490                                              int             seed);
1491 static void        container_destroy        (TestTypeNode   *node);
1492
1493
1494
1495 static const TestTypeNodeClass int32_class = {
1496   DBUS_TYPE_INT32,
1497   sizeof (TestTypeNode),
1498   NULL,
1499   NULL,
1500   int32_write_value,
1501   int32_read_value,
1502   NULL
1503 };
1504
1505 static const TestTypeNodeClass uint32_class = {
1506   DBUS_TYPE_UINT32,
1507   sizeof (TestTypeNode),
1508   NULL,
1509   NULL,
1510   int32_write_value, /* recycle from int32 */
1511   int32_read_value,  /* recycle from int32 */
1512   NULL
1513 };
1514
1515 static const TestTypeNodeClass int64_class = {
1516   DBUS_TYPE_INT64,
1517   sizeof (TestTypeNode),
1518   NULL,
1519   NULL,
1520   int64_write_value,
1521   int64_read_value,
1522   NULL
1523 };
1524
1525 static const TestTypeNodeClass uint64_class = {
1526   DBUS_TYPE_UINT64,
1527   sizeof (TestTypeNode),
1528   NULL,
1529   NULL,
1530   int64_write_value, /* recycle from int64 */
1531   int64_read_value,  /* recycle from int64 */
1532   NULL
1533 };
1534
1535 static const TestTypeNodeClass struct_1_class = {
1536   DBUS_TYPE_STRUCT,
1537   sizeof (TestTypeNodeContainer),
1538   NULL,
1539   container_destroy,
1540   struct_1_write_value,
1541   struct_1_read_value,
1542   struct_1_build_signature
1543 };
1544
1545 static const TestTypeNodeClass struct_2_class = {
1546   DBUS_TYPE_STRUCT,
1547   sizeof (TestTypeNodeContainer),
1548   NULL,
1549   container_destroy,
1550   struct_2_write_value,
1551   struct_2_read_value,
1552   struct_2_build_signature
1553 };
1554
1555 static const TestTypeNodeClass array_0_class = {
1556   DBUS_TYPE_ARRAY,
1557   sizeof (TestTypeNodeContainer),
1558   NULL,
1559   container_destroy,
1560   array_0_write_value,
1561   array_0_read_value,
1562   array_build_signature
1563 };
1564
1565 static const TestTypeNodeClass array_1_class = {
1566   DBUS_TYPE_ARRAY,
1567   sizeof (TestTypeNodeContainer),
1568   NULL,
1569   container_destroy,
1570   array_1_write_value,
1571   array_1_read_value,
1572   array_build_signature
1573 };
1574
1575 static const TestTypeNodeClass array_2_class = {
1576   DBUS_TYPE_ARRAY,
1577   sizeof (TestTypeNodeContainer),
1578   NULL,
1579   container_destroy,
1580   array_2_write_value,
1581   array_2_read_value,
1582   array_build_signature
1583 };
1584
1585 static const TestTypeNodeClass* const
1586 basic_nodes[] = {
1587   &int32_class,
1588   &uint32_class,
1589   &int64_class,
1590   &uint64_class
1591 };
1592 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
1593
1594 static const TestTypeNodeClass* const
1595 container_nodes[] = {
1596   &struct_1_class,
1597   &array_1_class,
1598   &struct_2_class,
1599   &array_0_class,
1600   &array_2_class
1601 };
1602 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
1603
1604 static TestTypeNode*
1605 node_new (const TestTypeNodeClass *klass)
1606 {
1607   TestTypeNode *node;
1608
1609   node = dbus_malloc0 (klass->instance_size);
1610   if (node == NULL)
1611     return NULL;
1612
1613   node->klass = klass;
1614
1615   if (klass->construct)
1616     {
1617       if (!(* klass->construct) (node))
1618         {
1619           dbus_free (node);
1620           return FALSE;
1621         }
1622     }
1623
1624   return node;
1625 }
1626
1627 static void
1628 node_destroy (TestTypeNode *node)
1629 {
1630   if (node->klass->destroy)
1631     (* node->klass->destroy) (node);
1632   dbus_free (node);
1633 }
1634
1635 static dbus_bool_t
1636 node_write_value (TestTypeNode   *node,
1637                   DataBlock      *block,
1638                   DBusTypeWriter *writer,
1639                   int             seed)
1640 {
1641   return (* node->klass->write_value) (node, block, writer, seed);
1642 }
1643
1644 static dbus_bool_t
1645 node_read_value (TestTypeNode   *node,
1646                  DataBlock      *block,
1647                  DBusTypeReader *reader,
1648                  int             seed)
1649 {
1650   return (* node->klass->read_value) (node, block, reader, seed);
1651 }
1652
1653 static dbus_bool_t
1654 node_build_signature (TestTypeNode *node,
1655                       DBusString   *str)
1656 {
1657   if (node->klass->build_signature)
1658     return (* node->klass->build_signature) (node, str);
1659   else
1660     return _dbus_string_append_byte (str, node->klass->typecode);
1661 }
1662
1663 static dbus_bool_t
1664 node_append_child (TestTypeNode *node,
1665                    TestTypeNode *child)
1666 {
1667   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
1668
1669   _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
1670
1671   if (!_dbus_list_append (&container->children, child))
1672     _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 */
1673
1674   return TRUE;
1675 }
1676
1677 typedef struct
1678 {
1679   const DBusString   *signature;
1680   DataBlock          *block;
1681   int                 type_offset;
1682   int                 byte_order;
1683   TestTypeNode      **nodes;
1684   int                 n_nodes;
1685 } NodeIterationData;
1686
1687 static dbus_bool_t
1688 run_test_nodes_iteration (void *data)
1689 {
1690   NodeIterationData *nid = data;
1691   DBusTypeReader reader;
1692   DBusTypeWriter writer;
1693   int i;
1694
1695   /* Stuff to do:
1696    * 1. write the value
1697    * 2. strcmp-compare with the signature we built
1698    * 3. read the value
1699    * 4. type-iterate the signature and the value and see if they are the same type-wise
1700    */
1701   data_block_init_reader_writer (nid->block,
1702                                  nid->byte_order,
1703                                  &reader, &writer);
1704
1705   i = 0;
1706   while (i < nid->n_nodes)
1707     {
1708       if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
1709         return FALSE;
1710
1711       ++i;
1712     }
1713
1714   if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
1715                                      &nid->block->signature, nid->type_offset))
1716     {
1717       _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
1718                   _dbus_string_get_const_data (nid->signature),
1719                   _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
1720                   nid->type_offset);
1721       _dbus_assert_not_reached ("wrong signature");
1722     }
1723
1724   i = 0;
1725   while (i < nid->n_nodes)
1726     {
1727       if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
1728         return FALSE;
1729
1730       if (i + 1 == nid->n_nodes)
1731         NEXT_EXPECTING_FALSE (&reader);
1732       else
1733         NEXT_EXPECTING_TRUE (&reader);
1734
1735       ++i;
1736     }
1737
1738   /* FIXME type-iterate both signature and value */
1739
1740   return TRUE;
1741 }
1742
1743 static void
1744 run_test_nodes_in_one_configuration (TestTypeNode    **nodes,
1745                                      int               n_nodes,
1746                                      const DBusString *signature,
1747                                      int               byte_order,
1748                                      int               initial_offset)
1749 {
1750   DataBlock block;
1751   NodeIterationData nid;
1752
1753   if (!data_block_init (&block))
1754     _dbus_assert_not_reached ("no memory");
1755
1756   if (!_dbus_string_lengthen (&block.signature, initial_offset))
1757     _dbus_assert_not_reached ("no memory");
1758
1759   if (!_dbus_string_lengthen (&block.body, initial_offset))
1760     _dbus_assert_not_reached ("no memory");
1761
1762   nid.signature = signature;
1763   nid.block = &block;
1764   nid.type_offset = initial_offset;
1765   nid.nodes = nodes;
1766   nid.n_nodes = n_nodes;
1767   nid.byte_order = byte_order;
1768
1769   /* FIXME put the OOM testing back once we debug everything and are willing to
1770    * wait for it to run ;-)
1771    */
1772 #if 0
1773   _dbus_test_oom_handling ("running test node",
1774                            run_test_nodes_iteration,
1775                            &nid);
1776 #else
1777   if (!run_test_nodes_iteration (&nid))
1778     _dbus_assert_not_reached ("no memory");
1779 #endif
1780
1781   data_block_free (&block);
1782 }
1783
1784 static void
1785 run_test_nodes (TestTypeNode **nodes,
1786                 int            n_nodes)
1787 {
1788   int i;
1789   DBusString signature;
1790
1791   if (!_dbus_string_init (&signature))
1792     _dbus_assert_not_reached ("no memory");
1793
1794   i = 0;
1795   while (i < n_nodes)
1796     {
1797       if (! node_build_signature (nodes[i], &signature))
1798         _dbus_assert_not_reached ("no memory");
1799
1800       ++i;
1801     }
1802
1803   _dbus_verbose (">>> test nodes with signature '%s'\n",
1804                  _dbus_string_get_const_data (&signature));
1805
1806   /* We do start offset 0 through 9, to get various alignment cases. Still this
1807    * obviously makes the test suite run 10x as slow.
1808    */
1809   i = 0;
1810   while (i < 10)
1811     {
1812       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1813                                            DBUS_LITTLE_ENDIAN, i);
1814       run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1815                                            DBUS_BIG_ENDIAN, i);
1816
1817       ++i;
1818     }
1819
1820   _dbus_string_free (&signature);
1821 }
1822
1823 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
1824
1825 static TestTypeNode*
1826 value_generator (int *ip)
1827 {
1828   int i = *ip;
1829   const TestTypeNodeClass *child_klass;
1830   const TestTypeNodeClass *container_klass;
1831   TestTypeNode *child;
1832   TestTypeNode *node;
1833
1834   _dbus_assert (i <= N_VALUES);
1835
1836   if (i == N_VALUES)
1837     {
1838       return NULL;
1839     }
1840   else if (i < N_BASICS)
1841     {
1842       node = node_new (basic_nodes[i]);
1843     }
1844   else
1845     {
1846       /* imagine an array:
1847        * container 0 of basic 0
1848        * container 0 of basic 1
1849        * container 0 of basic 2
1850        * container 1 of basic 0
1851        * container 1 of basic 1
1852        * container 1 of basic 2
1853        */
1854       i -= N_BASICS;
1855
1856       container_klass = container_nodes[i / N_BASICS];
1857       child_klass = basic_nodes[i % N_BASICS];
1858
1859       node = node_new (container_klass);
1860       child = node_new (child_klass);
1861
1862       node_append_child (node, child);
1863     }
1864
1865   *ip += 1; /* increment the generator */
1866
1867   return node;
1868 }
1869
1870 static void
1871 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
1872                                       int                      n_nested)
1873 {
1874   TestTypeNode *root;
1875   TestTypeNode *container;
1876   TestTypeNode *child;
1877   int i;
1878
1879   root = node_new (container_klass);
1880   container = root;
1881   for (i = 1; i < n_nested; i++)
1882     {
1883       child = node_new (container_klass);
1884       node_append_child (container, child);
1885       container = child;
1886     }
1887
1888   /* container should now be the most-nested container */
1889
1890   i = 0;
1891   while ((child = value_generator (&i)))
1892     {
1893       node_append_child (container, child);
1894
1895       run_test_nodes (&root, 1);
1896
1897       _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
1898       node_destroy (child);
1899     }
1900
1901   node_destroy (root);
1902 }
1903
1904 static void
1905 make_and_run_test_nodes (void)
1906 {
1907   int i, j, k, m;
1908
1909   /* We try to do this in order of "complicatedness" so that test
1910    * failures tend to show up in the simplest test case that
1911    * demonstrates the failure.  There are also some tests that run
1912    * more than once for this reason, first while going through simple
1913    * cases, second while going through a broader range of complex
1914    * cases.
1915    */
1916   /* Each basic node. The basic nodes should include:
1917    *
1918    * - each fixed-size type (in such a way that it has different values each time,
1919    *                         so we can tell if we mix two of them up)
1920    * - strings of length 0-9
1921    * - object path
1922    * - signature
1923    */
1924   /* Each container node. The container nodes should include:
1925    *
1926    *  struct with 1 and 2 copies of the contained item
1927    *  array with 0, 1, 2 copies of the contained item
1928    *  variant
1929    */
1930   /*  Let a "value" be a basic node, or a container containing a single basic node.
1931    *  Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
1932    *  When iterating through all values to make combinations, do the basic types
1933    *  first and the containers second.
1934    */
1935   /* Each item is shown with its number of iterations to complete so
1936    * we can keep a handle on this unit test
1937    */
1938
1939   /* FIXME test just an empty body, no types at all */
1940
1941   _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
1942                  N_VALUES);
1943   {
1944     TestTypeNode *node;
1945     i = 0;
1946     while ((node = value_generator (&i)))
1947       {
1948         run_test_nodes (&node, 1);
1949
1950         node_destroy (node);
1951       }
1952   }
1953
1954   _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
1955   {
1956     TestTypeNode *nodes[N_VALUES];
1957
1958     i = 0;
1959     while ((nodes[i] = value_generator (&i)))
1960       ;
1961
1962     run_test_nodes (nodes, N_VALUES);
1963
1964     for (i = 0; i < N_VALUES; i++)
1965       node_destroy (nodes[i]);
1966   }
1967
1968   _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
1969                  N_VALUES * N_VALUES * 2);
1970   {
1971     TestTypeNode *nodes[2];
1972
1973     i = 0;
1974     while ((nodes[0] = value_generator (&i)))
1975       {
1976         j = 0;
1977         while ((nodes[1] = value_generator (&j)))
1978           {
1979             run_test_nodes (nodes, 2);
1980
1981             node_destroy (nodes[1]);
1982           }
1983
1984         node_destroy (nodes[0]);
1985       }
1986   }
1987
1988   _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
1989                  N_CONTAINERS * N_VALUES);
1990   for (i = 0; i < N_CONTAINERS; i++)
1991     {
1992       const TestTypeNodeClass *container_klass = container_nodes[i];
1993
1994       make_and_run_values_inside_container (container_klass, 1);
1995     }
1996
1997   _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
1998                  N_CONTAINERS * N_VALUES);
1999   for (i = 0; i < N_CONTAINERS; i++)
2000     {
2001       const TestTypeNodeClass *container_klass = container_nodes[i];
2002
2003       make_and_run_values_inside_container (container_klass, 2);
2004     }
2005
2006   _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
2007                  N_CONTAINERS * N_VALUES);
2008   for (i = 0; i < N_CONTAINERS; i++)
2009     {
2010       const TestTypeNodeClass *container_klass = container_nodes[i];
2011
2012       make_and_run_values_inside_container (container_klass, 3);
2013     }
2014
2015   _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
2016                  N_VALUES * N_VALUES);
2017   {
2018     TestTypeNode *val1, *val2;
2019     TestTypeNode *node;
2020
2021     node = node_new (&struct_1_class);
2022
2023     i = 0;
2024     while ((val1 = value_generator (&i)))
2025       {
2026         j = 0;
2027         while ((val2 = value_generator (&j)))
2028           {
2029             TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2030
2031             node_append_child (node, val1);
2032             node_append_child (node, val2);
2033
2034             run_test_nodes (&node, 1);
2035
2036             _dbus_list_clear (&container->children);
2037             node_destroy (val2);
2038           }
2039         node_destroy (val1);
2040       }
2041     node_destroy (node);
2042   }
2043
2044   _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
2045   {
2046     TestTypeNode *node;
2047     TestTypeNode *child;
2048
2049     node = node_new (&struct_1_class);
2050
2051     i = 0;
2052     while ((child = value_generator (&i)))
2053       node_append_child (node, child);
2054
2055     run_test_nodes (&node, 1);
2056
2057     node_destroy (node);
2058   }
2059
2060   _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
2061                  N_CONTAINERS * N_CONTAINERS * N_VALUES);
2062   for (i = 0; i < N_CONTAINERS; i++)
2063     {
2064       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2065       TestTypeNode *outer_container = node_new (outer_container_klass);
2066
2067       for (j = 0; j < N_CONTAINERS; j++)
2068         {
2069           TestTypeNode *child;
2070           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2071           TestTypeNode *inner_container = node_new (inner_container_klass);
2072
2073           node_append_child (outer_container, inner_container);
2074
2075           m = 0;
2076           while ((child = value_generator (&m)))
2077             {
2078               node_append_child (inner_container, child);
2079
2080               run_test_nodes (&outer_container, 1);
2081
2082               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2083               node_destroy (child);
2084             }
2085           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2086           node_destroy (inner_container);
2087         }
2088       node_destroy (outer_container);
2089     }
2090
2091   _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
2092                  N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2093   for (i = 0; i < N_CONTAINERS; i++)
2094     {
2095       const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2096       TestTypeNode *outer_container = node_new (outer_container_klass);
2097
2098       for (j = 0; j < N_CONTAINERS; j++)
2099         {
2100           const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2101           TestTypeNode *inner_container = node_new (inner_container_klass);
2102
2103           node_append_child (outer_container, inner_container);
2104
2105           for (k = 0; k < N_CONTAINERS; k++)
2106             {
2107               TestTypeNode *child;
2108               const TestTypeNodeClass *center_container_klass = container_nodes[k];
2109               TestTypeNode *center_container = node_new (center_container_klass);
2110
2111               node_append_child (inner_container, center_container);
2112
2113               m = 0;
2114               while ((child = value_generator (&m)))
2115                 {
2116                   node_append_child (center_container, child);
2117
2118                   run_test_nodes (&outer_container, 1);
2119
2120                   _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2121                   node_destroy (child);
2122                 }
2123               _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2124               node_destroy (center_container);
2125             }
2126           _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2127           node_destroy (inner_container);
2128         }
2129       node_destroy (outer_container);
2130     }
2131
2132   _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2133                  N_VALUES * N_VALUES * N_VALUES);
2134   {
2135     TestTypeNode *nodes[3];
2136
2137     i = 0;
2138     while ((nodes[0] = value_generator (&i)))
2139       {
2140         j = 0;
2141         while ((nodes[1] = value_generator (&j)))
2142           {
2143             k = 0;
2144             while ((nodes[2] = value_generator (&k)))
2145               {
2146                 run_test_nodes (nodes, 3);
2147
2148                 node_destroy (nodes[2]);
2149               }
2150             node_destroy (nodes[1]);
2151           }
2152         node_destroy (nodes[0]);
2153       }
2154   }
2155 }
2156
2157 dbus_bool_t _dbus_marshal_recursive_test (void);
2158
2159 dbus_bool_t
2160 _dbus_marshal_recursive_test (void)
2161 {
2162   make_and_run_test_nodes ();
2163
2164   return TRUE;
2165 }
2166
2167 #if 1
2168 int
2169 main (int argc, char **argv)
2170 {
2171   _dbus_marshal_recursive_test ();
2172
2173   return 0;
2174 }
2175 #endif /* main() */
2176
2177
2178 /*
2179  *
2180  *
2181  *         Implementations of each type node class
2182  *
2183  *
2184  *
2185  */
2186
2187 static dbus_int32_t
2188 int32_from_seed (int seed)
2189 {
2190   /* Generate an integer value that's predictable from seed.  We could
2191    * just use seed itself, but that would only ever touch one byte of
2192    * the int so would miss some kinds of bug.
2193    */
2194   dbus_int32_t v;
2195
2196   v = 42; /* just to quiet compiler afaik */
2197   switch (seed % 5)
2198     {
2199     case 0:
2200       v = SAMPLE_INT32;
2201       break;
2202     case 1:
2203       v = SAMPLE_INT32_ALTERNATE;
2204       break;
2205     case 2:
2206       v = -1;
2207       break;
2208     case 3:
2209       v = _DBUS_INT_MAX;
2210       break;
2211     case 4:
2212       v = 1;
2213       break;
2214     }
2215
2216   if (seed > 1)
2217     v *= seed; /* wraps around eventually, which is fine */
2218
2219   return v;
2220 }
2221
2222 static dbus_bool_t
2223 int32_write_value (TestTypeNode   *node,
2224                    DataBlock      *block,
2225                    DBusTypeWriter *writer,
2226                    int             seed)
2227 {
2228   /* also used for uint32 */
2229   dbus_int32_t v;
2230
2231   v = int32_from_seed (seed);
2232
2233   return _dbus_type_writer_write_basic (writer,
2234                                         node->klass->typecode,
2235                                         &v);
2236 }
2237
2238 static dbus_bool_t
2239 int32_read_value (TestTypeNode   *node,
2240                   DataBlock      *block,
2241                   DBusTypeReader *reader,
2242                   int             seed)
2243 {
2244   /* also used for uint32 */
2245   dbus_int32_t v;
2246
2247   check_expected_type (reader, node->klass->typecode);
2248
2249   _dbus_type_reader_read_basic (reader,
2250                                 (dbus_int32_t*) &v);
2251
2252   _dbus_assert (v == int32_from_seed (seed));
2253
2254   return TRUE;
2255 }
2256
2257 #ifdef DBUS_HAVE_INT64
2258 static dbus_int64_t
2259 int64_from_seed (int seed)
2260 {
2261   dbus_int32_t v32;
2262   dbus_int64_t v;
2263   
2264   v32 = int32_from_seed (seed);
2265
2266   v = (((dbus_int64_t)v32) << 32) | (~v32);
2267   
2268   return v;
2269 }
2270 #endif
2271
2272 static dbus_bool_t
2273 int64_write_value (TestTypeNode   *node,
2274                    DataBlock      *block,
2275                    DBusTypeWriter *writer,
2276                    int             seed)
2277 {
2278 #ifdef DBUS_HAVE_INT64
2279   /* also used for uint64 */
2280   dbus_int64_t v;
2281
2282   v = int64_from_seed (seed);
2283
2284   return _dbus_type_writer_write_basic (writer,
2285                                         node->klass->typecode,
2286                                         &v);
2287 #else
2288   return TRUE;
2289 #endif
2290 }
2291
2292 static dbus_bool_t
2293 int64_read_value (TestTypeNode   *node,
2294                   DataBlock      *block,
2295                   DBusTypeReader *reader,
2296                   int             seed)
2297 {
2298 #ifdef DBUS_HAVE_INT64
2299   /* also used for uint64 */
2300   dbus_int64_t v;
2301
2302   check_expected_type (reader, node->klass->typecode);
2303
2304   _dbus_type_reader_read_basic (reader,
2305                                 (dbus_int64_t*) &v);
2306
2307   _dbus_assert (v == int64_from_seed (seed));
2308
2309   return TRUE;
2310 #else
2311   return TRUE;
2312 #endif
2313 }
2314
2315 static dbus_bool_t
2316 struct_N_write_value (TestTypeNode   *node,
2317                       DataBlock      *block,
2318                       DBusTypeWriter *writer,
2319                       int             n_copies)
2320 {
2321   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2322   DataBlockState saved;
2323   DBusTypeWriter sub;
2324   int i;
2325
2326   _dbus_assert (container->children != NULL);
2327
2328   data_block_save (block, &saved);
2329
2330   if (!_dbus_type_writer_recurse_struct (writer,
2331                                          &sub))
2332     return FALSE;
2333
2334   i = 0;
2335   while (i < n_copies)
2336     {
2337       DBusList *link;
2338
2339       link = _dbus_list_get_first_link (&container->children);
2340       while (link != NULL)
2341         {
2342           TestTypeNode *child = link->data;
2343           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2344
2345           if (!node_write_value (child, block, &sub, i))
2346             {
2347               data_block_restore (block, &saved);
2348               return FALSE;
2349             }
2350
2351           link = next;
2352         }
2353
2354       ++i;
2355     }
2356
2357   if (!_dbus_type_writer_unrecurse (writer, &sub))
2358     {
2359       data_block_restore (block, &saved);
2360       return FALSE;
2361     }
2362
2363   return TRUE;
2364 }
2365
2366 static dbus_bool_t
2367 struct_N_read_value (TestTypeNode   *node,
2368                      DataBlock      *block,
2369                      DBusTypeReader *reader,
2370                      int             n_copies)
2371 {
2372   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2373   DBusTypeReader sub;
2374   int i;
2375
2376   check_expected_type (reader, DBUS_TYPE_STRUCT);
2377
2378   _dbus_type_reader_recurse (reader, &sub);
2379
2380   i = 0;
2381   while (i < n_copies)
2382     {
2383       DBusList *link;
2384
2385       link = _dbus_list_get_first_link (&container->children);
2386       while (link != NULL)
2387         {
2388           TestTypeNode *child = link->data;
2389           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2390
2391           if (!node_read_value (child, block, &sub, i))
2392             return FALSE;
2393
2394           if (i == (n_copies - 1) && next == NULL)
2395             NEXT_EXPECTING_FALSE (&sub);
2396           else
2397             NEXT_EXPECTING_TRUE (&sub);
2398
2399           link = next;
2400         }
2401
2402       ++i;
2403     }
2404
2405   return TRUE;
2406 }
2407
2408 static dbus_bool_t
2409 struct_N_build_signature (TestTypeNode   *node,
2410                           DBusString     *str,
2411                           int             n_copies)
2412 {
2413   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2414   int i;
2415   int orig_len;
2416
2417   orig_len = _dbus_string_get_length (str);
2418
2419   if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
2420     goto oom;
2421
2422   i = 0;
2423   while (i < n_copies)
2424     {
2425       DBusList *link;
2426
2427       link = _dbus_list_get_first_link (&container->children);
2428       while (link != NULL)
2429         {
2430           TestTypeNode *child = link->data;
2431           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2432
2433           if (!node_build_signature (child, str))
2434             goto oom;
2435
2436           link = next;
2437         }
2438
2439       ++i;
2440     }
2441
2442   if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
2443     goto oom;
2444
2445   return TRUE;
2446
2447  oom:
2448   _dbus_string_set_length (str, orig_len);
2449   return FALSE;
2450 }
2451
2452 static dbus_bool_t
2453 struct_1_write_value (TestTypeNode   *node,
2454                       DataBlock      *block,
2455                       DBusTypeWriter *writer,
2456                       int             seed)
2457 {
2458   return struct_N_write_value (node, block, writer, 1);
2459 }
2460
2461 static dbus_bool_t
2462 struct_1_read_value (TestTypeNode   *node,
2463                      DataBlock      *block,
2464                      DBusTypeReader *reader,
2465                      int             seed)
2466 {
2467   return struct_N_read_value (node, block, reader, 1);
2468 }
2469
2470 static dbus_bool_t
2471 struct_1_build_signature (TestTypeNode   *node,
2472                           DBusString     *str)
2473 {
2474   return struct_N_build_signature (node, str, 1);
2475 }
2476
2477
2478 static dbus_bool_t
2479 struct_2_write_value (TestTypeNode   *node,
2480                       DataBlock      *block,
2481                       DBusTypeWriter *writer,
2482                       int             seed)
2483 {
2484   return struct_N_write_value (node, block, writer, 2);
2485 }
2486
2487 static dbus_bool_t
2488 struct_2_read_value (TestTypeNode   *node,
2489                      DataBlock      *block,
2490                      DBusTypeReader *reader,
2491                      int             seed)
2492 {
2493   return struct_N_read_value (node, block, reader, 2);
2494 }
2495
2496 static dbus_bool_t
2497 struct_2_build_signature (TestTypeNode   *node,
2498                           DBusString     *str)
2499 {
2500   return struct_N_build_signature (node, str, 2);
2501 }
2502
2503 static dbus_bool_t
2504 array_N_write_value (TestTypeNode   *node,
2505                      DataBlock      *block,
2506                      DBusTypeWriter *writer,
2507                      int             n_copies)
2508 {
2509   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2510   DataBlockState saved;
2511   DBusTypeWriter sub;
2512   DBusString element_signature;
2513   int i;
2514
2515   _dbus_assert (container->children != NULL);
2516
2517   data_block_save (block, &saved);
2518
2519   if (!_dbus_string_init (&element_signature))
2520     return FALSE;
2521
2522   if (!node_build_signature (_dbus_list_get_first (&container->children),
2523                              &element_signature))
2524     goto oom;
2525
2526   if (!_dbus_type_writer_recurse_array (writer,
2527                                         _dbus_string_get_const_data (&element_signature),
2528                                         &sub))
2529     goto oom;
2530
2531   i = 0;
2532   while (i < n_copies)
2533     {
2534       DBusList *link;
2535
2536       link = _dbus_list_get_first_link (&container->children);
2537       while (link != NULL)
2538         {
2539           TestTypeNode *child = link->data;
2540           DBusList *next = _dbus_list_get_next_link (&container->children, link);
2541
2542           if (!node_write_value (child, block, &sub, i))
2543             goto oom;
2544
2545           link = next;
2546         }
2547
2548       ++i;
2549     }
2550
2551   if (!_dbus_type_writer_unrecurse (writer, &sub))
2552     goto oom;
2553
2554   return TRUE;
2555
2556  oom:
2557   data_block_restore (block, &saved);
2558   _dbus_string_free (&element_signature);
2559   return FALSE;
2560 }
2561
2562 static dbus_bool_t
2563 array_N_read_value (TestTypeNode   *node,
2564                     DataBlock      *block,
2565                     DBusTypeReader *reader,
2566                     int             n_copies)
2567 {
2568   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2569   DBusTypeReader sub;
2570   int i;
2571
2572   check_expected_type (reader, DBUS_TYPE_ARRAY);
2573
2574   if (n_copies > 0)
2575     {
2576       _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
2577
2578       _dbus_type_reader_recurse (reader, &sub);
2579
2580       i = 0;
2581       while (i < n_copies)
2582         {
2583           DBusList *link;
2584
2585           link = _dbus_list_get_first_link (&container->children);
2586           while (link != NULL)
2587             {
2588               TestTypeNode *child = link->data;
2589               DBusList *next = _dbus_list_get_next_link (&container->children, link);
2590
2591               if (!node_read_value (child, block, &sub, i))
2592                 return FALSE;
2593
2594               if (i == (n_copies - 1) && next == NULL)
2595                 NEXT_EXPECTING_FALSE (&sub);
2596               else
2597                 NEXT_EXPECTING_TRUE (&sub);
2598
2599               link = next;
2600             }
2601
2602           ++i;
2603         }
2604     }
2605   else
2606     {
2607       _dbus_assert (_dbus_type_reader_array_is_empty (reader));
2608     }
2609
2610   return TRUE;
2611 }
2612
2613 static dbus_bool_t
2614 array_build_signature (TestTypeNode   *node,
2615                        DBusString     *str)
2616 {
2617   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2618   int orig_len;
2619
2620   orig_len = _dbus_string_get_length (str);
2621
2622   if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
2623     goto oom;
2624
2625   if (!node_build_signature (_dbus_list_get_first (&container->children),
2626                              str))
2627     goto oom;
2628
2629   return TRUE;
2630
2631  oom:
2632   _dbus_string_set_length (str, orig_len);
2633   return FALSE;
2634 }
2635
2636 static dbus_bool_t
2637 array_0_write_value (TestTypeNode   *node,
2638                      DataBlock      *block,
2639                      DBusTypeWriter *writer,
2640                      int             seed)
2641 {
2642   return array_N_write_value (node, block, writer, 0);
2643 }
2644
2645 static dbus_bool_t
2646 array_0_read_value (TestTypeNode   *node,
2647                     DataBlock      *block,
2648                     DBusTypeReader *reader,
2649                     int             seed)
2650 {
2651   return array_N_read_value (node, block, reader, 0);
2652 }
2653
2654
2655 static dbus_bool_t
2656 array_1_write_value (TestTypeNode   *node,
2657                      DataBlock      *block,
2658                      DBusTypeWriter *writer,
2659                      int             seed)
2660 {
2661   return array_N_write_value (node, block, writer, 1);
2662 }
2663
2664 static dbus_bool_t
2665 array_1_read_value (TestTypeNode   *node,
2666                     DataBlock      *block,
2667                     DBusTypeReader *reader,
2668                        int          seed)
2669 {
2670   return array_N_read_value (node, block, reader, 1);
2671 }
2672
2673 static dbus_bool_t
2674 array_2_write_value (TestTypeNode   *node,
2675                      DataBlock      *block,
2676                      DBusTypeWriter *writer,
2677                      int             seed)
2678 {
2679   return array_N_write_value (node, block, writer, 2);
2680 }
2681
2682 static dbus_bool_t
2683 array_2_read_value (TestTypeNode   *node,
2684                     DataBlock      *block,
2685                     DBusTypeReader *reader,
2686                     int             seed)
2687 {
2688   return array_N_read_value (node, block, reader, 2);
2689 }
2690
2691 static void
2692 container_destroy (TestTypeNode *node)
2693 {
2694   TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2695   DBusList *link;
2696
2697   link = _dbus_list_get_first_link (&container->children);
2698   while (link != NULL)
2699     {
2700       TestTypeNode *child = link->data;
2701       DBusList *next = _dbus_list_get_next_link (&container->children, link);
2702
2703       node_destroy (child);
2704
2705       _dbus_list_free_link (link);
2706
2707       link = next;
2708     }
2709 }
2710
2711 #endif /* DBUS_BUILD_TESTS */