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