switch to a vtable approach for the reader
[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 void
557 _dbus_type_writer_init (DBusTypeWriter *writer,
558                         int             byte_order,
559                         DBusString     *type_str,
560                         int             type_pos,
561                         DBusString     *value_str,
562                         int             value_pos)
563 {
564   writer->byte_order = byte_order;
565   writer->type_str = type_str;
566   writer->type_pos = type_pos;
567   writer->value_str = value_str;
568   writer->value_pos = value_pos;
569   writer->container_type = DBUS_TYPE_INVALID;
570   writer->inside_array = FALSE;
571
572   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
573                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
574 }
575
576 static dbus_bool_t
577 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
578                                            int             type,
579                                            const void     *value)
580 {
581   int old_value_len;
582   int bytes_written;
583
584   old_value_len = _dbus_string_get_length (writer->value_str);
585         
586   if (!_dbus_marshal_basic_type (writer->value_str,
587                                  writer->value_pos,
588                                  type,
589                                  value,
590                                  writer->byte_order))
591     return FALSE;
592
593   bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
594   
595   writer->value_pos += bytes_written;
596
597   return TRUE;
598 }
599
600 /* If our parent is an array, things are a little bit complicated.
601  *
602  * The parent must have a complete element type, such as
603  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
604  * unclosed parens, or an "a" with no following type.
605  *
606  * To recurse, the only allowed operation is to recurse into the
607  * first type in the element type. So for "i" you can't recurse, for
608  * "ai" you can recurse into the array, for "(ii)" you can recurse
609  * into the struct.
610  *
611  * If you recurse into the array for "ai", then you must specify
612  * "i" for the element type of the array you recurse into.
613  * 
614  * While inside an array at any level, we need to avoid writing to
615  * type_str, since the type only appears once for the whole array,
616  * it does not appear for each array element.
617  *
618  * While inside an array type_pos points to the expected next
619  * typecode, rather than the next place we could write a typecode.
620  */
621 static void
622 writer_recurse_init_and_check (DBusTypeWriter *writer,
623                                int             container_type,
624                                DBusTypeWriter *sub)
625 {
626   _dbus_type_writer_init (sub,
627                           writer->byte_order,
628                           writer->type_str,
629                           writer->type_pos,
630                           writer->value_str,
631                           writer->value_pos);
632   
633   sub->container_type = container_type;
634
635   if (writer->inside_array || sub->container_type == DBUS_TYPE_ARRAY)
636     sub->inside_array = TRUE;
637   else
638     sub->inside_array = FALSE;
639   
640 #ifndef DBUS_DISABLE_CHECKS
641   if (writer->inside_array)
642     {
643       int expected;
644
645       expected = first_type_in_signature (writer->type_str, writer->type_pos);
646       
647       if (expected != sub->container_type)
648         {
649           _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
650                       _dbus_type_to_string (sub->container_type),
651                       _dbus_type_to_string (expected));
652           _dbus_assert_not_reached ("bad array element written");
653         }
654     }
655 #endif /* DBUS_DISABLE_CHECKS */
656
657   _dbus_verbose ("  type writer %p recurse parent type_pos = %d value_pos = %d inside_array = %d container_type = %s remaining sig '%s'\n",
658                  writer, writer->type_pos, writer->value_pos, writer->inside_array,
659                  _dbus_type_to_string (writer->container_type),
660                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
661   _dbus_verbose ("  type writer %p recurse sub    type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
662                  sub, sub->type_pos, sub->value_pos,
663                  sub->inside_array,
664                  _dbus_type_to_string (sub->container_type));
665 }
666
667 static dbus_bool_t
668 write_or_verify_typecode (DBusTypeWriter *writer,
669                           int             typecode)
670 {
671   /* A subwriter inside an array will have type_pos pointing to the
672    * expected typecode; a writer not inside an array has type_pos
673    * pointing to the next place to insert a typecode.
674    */
675   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
676                  writer, writer->type_pos,
677                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
678   
679   if (writer->inside_array)
680     {
681 #ifndef DBUS_DISABLE_CHECKS
682       {
683         int expected;
684         
685         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
686         
687         if (expected != typecode)
688           {
689             _dbus_warn ("Array type requires that type %s be written, but %s was written\n",
690                         _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
691             _dbus_assert_not_reached ("bad type inserted somewhere inside an array");
692           }
693       }
694 #endif /* DBUS_DISABLE_CHECKS */
695
696       /* if immediately inside an array we'd always be appending an element,
697        * so the expected type doesn't change; if inside a struct or something
698        * below an array, we need to move through said struct or something.
699        */
700       if (writer->container_type != DBUS_TYPE_ARRAY)
701         writer->type_pos += 1;
702     }
703   else
704     {
705       if (!_dbus_string_insert_byte (writer->type_str,
706                                      writer->type_pos,
707                                      typecode))
708         return FALSE;
709
710       writer->type_pos += 1;
711     }
712
713   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
714                  writer, writer->type_pos,
715                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
716   
717   return TRUE;
718 }
719
720 dbus_bool_t
721 _dbus_type_writer_recurse (DBusTypeWriter *writer,
722                            int             container_type,
723                            DBusTypeWriter *sub)
724 {
725   writer_recurse_init_and_check (writer, container_type, sub);
726   
727   switch (container_type)
728     {
729     case DBUS_TYPE_STRUCT:
730       {
731         /* Ensure that we'll be able to add alignment padding and the typecode */
732         if (!_dbus_string_alloc_space (sub->value_str, 8))
733           return FALSE;
734
735         if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
736           _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
737         
738         if (!_dbus_string_insert_bytes (sub->value_str,
739                                         sub->value_pos,
740                                         _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
741                                         '\0'))
742           _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
743         sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
744       }
745       break;
746     case DBUS_TYPE_ARRAY:
747       _dbus_assert_not_reached ("use recurse_array() for arrays");
748       break;
749     default:
750       _dbus_assert_not_reached ("container_type unhandled");
751       break;
752     }
753   
754   return TRUE;
755 }
756
757 dbus_bool_t
758 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
759                                  const char     *element_type,
760                                  DBusTypeWriter *sub)
761 {
762   int element_type_len;
763   DBusString element_type_str;
764   dbus_uint32_t value = 0;
765   int alignment;
766   int aligned;
767   DBusString str;
768   
769   writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
770   
771 #ifndef DBUS_DISABLE_CHECKS
772   if (writer->container_type == DBUS_TYPE_ARRAY)
773     {
774       DBusString parent_elements;
775
776       _dbus_assert (element_type != NULL);
777       
778       _dbus_string_init_const (&parent_elements,
779                                _dbus_string_get_const_data_len (writer->type_str,
780                                                                 writer->u.array.element_type_pos + 1,
781                                                                 0));
782                                                                 
783       if (!_dbus_string_starts_with_c_str (&parent_elements, element_type))
784         {
785           _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
786                       element_type);
787           _dbus_assert_not_reached ("incompatible type for child array");
788         }
789     }
790 #endif /* DBUS_DISABLE_CHECKS */
791   
792   _dbus_string_init_const (&element_type_str, element_type);
793   element_type_len = _dbus_string_get_length (&element_type_str);
794
795   /* 4 bytes for the array length and 4 bytes possible padding */
796   if (!_dbus_string_alloc_space (sub->value_str, 8))
797     return FALSE;
798
799   sub->type_pos += 1; /* move to point to the element type, since type_pos
800                        * should be the expected type for further writes
801                        */
802   sub->u.array.element_type_pos = sub->type_pos;
803   sub->u.array.element_type_len = element_type_len;
804
805   if (!writer->inside_array)
806     {
807       /* sub is a toplevel/outermost array so we need to write the type data */
808       
809       /* alloc space for array typecode, element signature, possible 7
810        * bytes of padding
811        */
812       if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
813         return FALSE;
814
815       if (!_dbus_string_insert_byte (writer->type_str,
816                                      writer->type_pos,
817                                      DBUS_TYPE_ARRAY))
818         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
819
820       if (!_dbus_string_copy (&element_type_str, 0,
821                               sub->type_str, sub->u.array.element_type_pos))
822         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
823     }
824
825   /* Write the length */
826   sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
827
828   if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
829                                                   &value))
830     _dbus_assert_not_reached ("should not have failed to insert array len");
831   
832   _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
833
834   /* Write alignment padding for array elements */
835   _dbus_string_init_const (&str, element_type);
836   alignment = element_type_get_alignment (&str, 0);
837
838   aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
839   if (aligned != sub->value_pos)
840     {
841       if (!_dbus_string_insert_bytes (sub->value_str,
842                                       sub->value_pos,
843                                       aligned - sub->value_pos,
844                                       '\0'))
845         _dbus_assert_not_reached ("should not have failed to insert alignment padding");
846       
847       sub->value_pos = aligned;
848     }
849   sub->u.array.start_pos = sub->value_pos;
850
851   _dbus_assert (sub->u.array.start_pos == sub->value_pos);
852   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
853
854   _dbus_verbose ("  type writer %p recurse array done remaining sig '%s'\n", sub,
855                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
856   
857   return TRUE;
858 }
859
860 dbus_bool_t
861 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
862                              DBusTypeWriter *sub)
863 {
864   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
865
866   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
867                  writer, writer->type_pos, writer->value_pos, writer->inside_array,
868                  _dbus_type_to_string (writer->container_type));
869   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
870                  sub, sub->type_pos, sub->value_pos,
871                  sub->inside_array,
872                  _dbus_type_to_string (sub->container_type));
873   
874   if (sub->container_type == DBUS_TYPE_STRUCT)
875     {
876       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
877         return FALSE;
878     }
879   else if (sub->container_type == DBUS_TYPE_ARRAY)
880     {
881       dbus_uint32_t len;
882
883       /* Set the array length */
884       len = sub->value_pos - sub->u.array.start_pos;
885       _dbus_marshal_set_uint32 (sub->value_str,
886                                 sub->byte_order,
887                                 sub->u.array.len_pos,
888                                 len);
889       _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
890                      len, sub->u.array.len_pos);
891     }
892
893   /* Now get type_pos right for the parent writer. Here are the cases:
894    *
895    * Cases !writer->inside_array:
896    *   (in these cases we want to update to the new insertion point)
897    * 
898    * - we recursed from STRUCT or INVALID into STRUCT and type_pos
899    *   is the new insertion point in all cases
900    *       writer->type_pos = sub->type_pos
901    * 
902    * - we recursed from STRUCT or INVALID into ARRAY, so type_pos in
903    *   the child is the array element type, and type_pos in the parent
904    *   currently is the child array type but should be set to the
905    *   insertion point just after the element type
906    *       writer->type_pos = sub->element_type_pos + sub->element_type_len
907    *
908    * Cases where writer->inside_array:
909    *   (in these cases we want to update to next expected write)
910    * 
911    * - we recursed from STRUCT into STRUCT somewhere inside an array
912    *   element; type_pos in parent is at the child's begin_struct, and
913    *   type_pos in the child is at the next field type for the parent
914    *       writer->type_pos = sub->type_pos
915    *
916    * - we recursed from STRUCT or INVALID into ARRAY somewhere inside
917    *   an array element, so type_pos in the parent is at the child's
918    *   array typecode, and type_pos in the child is at the array
919    *   element type
920    *       writer->type_pos = sub->element_type_pos + sub->element_type_len
921    * 
922    * - we recursed from ARRAY into STRUCT, so type_pos in the
923    *   parent is the element type starting with STRUCT,
924    *   and type_pos in the child is just after the end_struct code
925    *       writer->type_pos should remain as-is
926    * 
927    * - we recursed from ARRAY into ARRAY, so type_pos in the
928    *   parent is the element type starting with child's ARRAY code,
929    *   type_pos in the child is the element type of the
930    *   sub-array
931    *       writer->type_pos should remain as-is
932    */
933   if (writer->container_type == DBUS_TYPE_ARRAY)
934     {
935       /* Don't do anything, because sub was an element, and the type
936        * of subsequent elements should be the same
937        */
938     }
939   else if (sub->container_type == DBUS_TYPE_ARRAY)
940     {
941       /* Jump to the next type in the parent's type signature,
942        * which is after our array element type
943        */
944       _dbus_assert (writer->container_type != DBUS_TYPE_ARRAY);
945       writer->type_pos = sub->u.array.element_type_pos + sub->u.array.element_type_len;
946     }
947   else
948     {
949       writer->type_pos = sub->type_pos;
950     }
951   
952   writer->value_pos = sub->value_pos;
953
954   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
955                  writer, writer->type_pos, writer->value_pos,
956                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
957   
958   return TRUE;
959 }
960
961 dbus_bool_t
962 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
963                                int             type,
964                                const void     *value)
965 {
966   dbus_bool_t retval;
967   
968   /* First ensure that our type realloc will succeed */
969   if (!_dbus_string_alloc_space (writer->type_str, 1))
970     return FALSE;
971
972   retval = FALSE;
973
974   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
975     goto out;
976   
977   if (!write_or_verify_typecode (writer, type))
978     _dbus_assert_not_reached ("failed to write typecode after prealloc");
979   
980   retval = TRUE;
981   
982  out:
983   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d inside_array = %d\n",
984                  writer, writer->type_pos, writer->value_pos, writer->inside_array);
985   
986   return retval;
987 }
988
989 dbus_bool_t
990 _dbus_type_writer_write_array (DBusTypeWriter *writer,
991                                int             type,
992                                const void     *array,
993                                int             array_len)
994 {
995
996
997 }
998
999 /** @} */ /* end of DBusMarshal group */
1000
1001 #ifdef DBUS_BUILD_TESTS
1002 #include "dbus-test.h"
1003 #include <stdio.h>
1004 #include <stdlib.h>
1005
1006 typedef struct
1007 {
1008   DBusString signature;
1009   DBusString body;
1010 } DataBlock;
1011
1012 typedef struct
1013 {
1014   int saved_sig_len;
1015   int saved_body_len;
1016 } DataBlockState;
1017
1018 static dbus_bool_t
1019 data_block_init (DataBlock *block)
1020 {
1021   if (!_dbus_string_init (&block->signature))
1022     return FALSE;
1023
1024   if (!_dbus_string_init (&block->body))
1025     {
1026       _dbus_string_free (&block->signature);
1027       return FALSE;
1028     }
1029   
1030   return TRUE;
1031 }
1032
1033 static void
1034 data_block_free (DataBlock *block)
1035 {
1036   _dbus_string_free (&block->signature);
1037   _dbus_string_free (&block->body);
1038 }
1039
1040 static void
1041 data_block_save (DataBlock      *block,
1042                  DataBlockState *state)
1043 {
1044   state->saved_sig_len = _dbus_string_get_length (&block->signature);
1045   state->saved_body_len = _dbus_string_get_length (&block->body);
1046 }
1047
1048 static void
1049 data_block_restore (DataBlock      *block,
1050                     DataBlockState *state)
1051 {
1052   /* These set_length should be shortening things so should always work */
1053   
1054   if (!_dbus_string_set_length (&block->signature,
1055                                 state->saved_sig_len))
1056     _dbus_assert_not_reached ("could not restore signature length");
1057   
1058   if (!_dbus_string_set_length (&block->body,
1059                                 state->saved_body_len))
1060     _dbus_assert_not_reached ("could not restore body length");
1061 }
1062
1063 static void
1064 data_block_init_reader_writer (DataBlock      *block,
1065                                int             byte_order,
1066                                DBusTypeReader *reader,
1067                                DBusTypeWriter *writer)
1068 {
1069   _dbus_type_reader_init (reader,
1070                           byte_order,
1071                           &block->signature,
1072                           _dbus_string_get_length (&block->signature),
1073                           &block->body,
1074                           _dbus_string_get_length (&block->body));
1075   
1076   _dbus_type_writer_init (writer,
1077                           byte_order,
1078                           &block->signature,
1079                           _dbus_string_get_length (&block->signature),
1080                           &block->body,
1081                           _dbus_string_get_length (&block->body));
1082 }
1083
1084 #define NEXT_EXPECTING_TRUE(reader)  do { if (!_dbus_type_reader_next (reader))         \
1085  {                                                                                      \
1086     _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n",        \
1087                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1088     _dbus_assert_not_reached ("test failed");                                           \
1089  }                                                                                      \
1090 } while (0)
1091
1092 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader))          \
1093  {                                                                                      \
1094     _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n",       \
1095                               _DBUS_FUNCTION_NAME, __LINE__);                           \
1096     _dbus_assert_not_reached ("test failed");                                           \
1097  }                                                                                      \
1098  check_expected_type (reader, DBUS_TYPE_INVALID);                                       \
1099 } while (0)
1100
1101 #define SAMPLE_INT32           12345678
1102 #define SAMPLE_INT32_ALTERNATE 53781429
1103 static dbus_bool_t
1104 write_int32 (DataBlock      *block,
1105              DBusTypeWriter *writer)
1106 {
1107   dbus_int32_t v = SAMPLE_INT32;
1108
1109   return _dbus_type_writer_write_basic (writer,
1110                                         DBUS_TYPE_INT32,
1111                                         &v);
1112 }
1113
1114 static void
1115 real_check_expected_type (DBusTypeReader *reader,
1116                           int             expected,
1117                           const char     *funcname,
1118                           int             line)
1119 {
1120   int t;
1121
1122   t = _dbus_type_reader_get_current_type (reader);
1123   
1124   if (t != expected)
1125     {
1126       _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1127                   _dbus_type_to_string (t),
1128                   _dbus_type_to_string (expected),
1129                   funcname, line);
1130       
1131       exit (1);
1132     }
1133 }
1134
1135 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1136
1137 static dbus_bool_t
1138 read_int32 (DataBlock      *block,
1139             DBusTypeReader *reader)
1140 {
1141   dbus_int32_t v;
1142
1143   check_expected_type (reader, DBUS_TYPE_INT32);
1144   
1145   _dbus_type_reader_read_basic (reader,
1146                                 (dbus_int32_t*) &v);
1147
1148   _dbus_assert (v == SAMPLE_INT32);
1149
1150   return TRUE;
1151 }
1152
1153 static dbus_bool_t
1154 write_struct_of_int32 (DataBlock      *block,
1155                        DBusTypeWriter *writer)
1156 {
1157   dbus_int32_t v;
1158   DataBlockState saved;
1159   DBusTypeWriter sub;
1160
1161   data_block_save (block, &saved);
1162   
1163   if (!_dbus_type_writer_recurse (writer,
1164                                   DBUS_TYPE_STRUCT,
1165                                   &sub))
1166     return FALSE;
1167
1168   v = SAMPLE_INT32;
1169   if (!_dbus_type_writer_write_basic (&sub,
1170                                       DBUS_TYPE_INT32,
1171                                       &v))
1172     {
1173       data_block_restore (block, &saved);
1174       return FALSE;
1175     }
1176
1177   v = SAMPLE_INT32_ALTERNATE;
1178   if (!_dbus_type_writer_write_basic (&sub,
1179                                       DBUS_TYPE_INT32,
1180                                       &v))
1181     {
1182       data_block_restore (block, &saved);
1183       return FALSE;
1184     }
1185
1186   if (!_dbus_type_writer_unrecurse (writer, &sub))
1187     {
1188       data_block_restore (block, &saved);
1189       return FALSE;
1190     }
1191   
1192   return TRUE;
1193 }
1194
1195 static dbus_bool_t
1196 read_struct_of_int32 (DataBlock      *block,
1197                       DBusTypeReader *reader)
1198 {
1199   dbus_int32_t v;
1200   DBusTypeReader sub;
1201
1202   check_expected_type (reader, DBUS_TYPE_STRUCT);
1203   
1204   _dbus_type_reader_recurse (reader, &sub);
1205
1206   check_expected_type (&sub, DBUS_TYPE_INT32);
1207   
1208   _dbus_type_reader_read_basic (&sub,
1209                                 (dbus_int32_t*) &v);
1210
1211   _dbus_assert (v == SAMPLE_INT32);
1212
1213   NEXT_EXPECTING_TRUE (&sub);
1214   check_expected_type (&sub, DBUS_TYPE_INT32);
1215   
1216   _dbus_type_reader_read_basic (&sub,
1217                                 (dbus_int32_t*) &v);
1218
1219   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1220
1221   NEXT_EXPECTING_FALSE (&sub);
1222   
1223   return TRUE;
1224 }
1225
1226 static dbus_bool_t
1227 write_struct_of_structs (DataBlock      *block,
1228                          DBusTypeWriter *writer)
1229 {
1230   DataBlockState saved;
1231   DBusTypeWriter sub;
1232
1233   data_block_save (block, &saved);
1234   
1235   if (!_dbus_type_writer_recurse (writer,
1236                                   DBUS_TYPE_STRUCT,
1237                                   &sub))
1238     return FALSE;
1239
1240   if (!write_struct_of_int32 (block, &sub))
1241     {
1242       data_block_restore (block, &saved);
1243       return FALSE;
1244     }
1245   if (!write_struct_of_int32 (block, &sub))
1246     {
1247       data_block_restore (block, &saved);
1248       return FALSE;
1249     }
1250   if (!write_struct_of_int32 (block, &sub))
1251     {
1252       data_block_restore (block, &saved);
1253       return FALSE;
1254     }
1255
1256   if (!_dbus_type_writer_unrecurse (writer, &sub))
1257     {
1258       data_block_restore (block, &saved);
1259       return FALSE;
1260     }
1261   
1262   return TRUE;
1263 }
1264
1265 static dbus_bool_t
1266 read_struct_of_structs (DataBlock      *block,
1267                         DBusTypeReader *reader)
1268 {
1269   DBusTypeReader sub;
1270   
1271   check_expected_type (reader, DBUS_TYPE_STRUCT);
1272   
1273   _dbus_type_reader_recurse (reader, &sub);
1274
1275   if (!read_struct_of_int32 (block, &sub))
1276     return FALSE;
1277
1278   NEXT_EXPECTING_TRUE (&sub);
1279   if (!read_struct_of_int32 (block, &sub))
1280     return FALSE;
1281
1282   NEXT_EXPECTING_TRUE (&sub);
1283   if (!read_struct_of_int32 (block, &sub))
1284     return FALSE;
1285   
1286   NEXT_EXPECTING_FALSE (&sub);
1287   
1288   return TRUE;
1289 }
1290
1291 static dbus_bool_t
1292 write_struct_of_structs_of_structs (DataBlock      *block,
1293                                     DBusTypeWriter *writer)
1294 {
1295   DataBlockState saved;
1296   DBusTypeWriter sub;
1297
1298   data_block_save (block, &saved);
1299   
1300   if (!_dbus_type_writer_recurse (writer,
1301                                   DBUS_TYPE_STRUCT,
1302                                   &sub))
1303     return FALSE;
1304
1305   if (!write_struct_of_structs (block, &sub))
1306     {
1307       data_block_restore (block, &saved);
1308       return FALSE;
1309     }
1310   if (!write_struct_of_structs (block, &sub))
1311     {
1312       data_block_restore (block, &saved);
1313       return FALSE;
1314     }
1315
1316   if (!_dbus_type_writer_unrecurse (writer, &sub))
1317     {
1318       data_block_restore (block, &saved);
1319       return FALSE;
1320     }
1321   
1322   return TRUE;
1323 }
1324
1325 static dbus_bool_t
1326 read_struct_of_structs_of_structs (DataBlock      *block,
1327                                    DBusTypeReader *reader)
1328 {
1329   DBusTypeReader sub;
1330   
1331   check_expected_type (reader, DBUS_TYPE_STRUCT);
1332   
1333   _dbus_type_reader_recurse (reader, &sub);
1334
1335   if (!read_struct_of_structs (block, &sub))
1336     return FALSE;
1337
1338   NEXT_EXPECTING_TRUE (&sub);
1339   if (!read_struct_of_structs (block, &sub))
1340     return FALSE;
1341
1342   NEXT_EXPECTING_FALSE (&sub);
1343   
1344   return TRUE;
1345 }
1346
1347 static dbus_bool_t
1348 write_array_of_int32 (DataBlock      *block,
1349                       DBusTypeWriter *writer)
1350 {
1351   dbus_int32_t v;
1352   DataBlockState saved;
1353   DBusTypeWriter sub;
1354
1355   data_block_save (block, &saved);
1356   
1357   if (!_dbus_type_writer_recurse_array (writer,
1358                                         DBUS_TYPE_INT32_AS_STRING,
1359                                         &sub))
1360     return FALSE;
1361
1362   v = SAMPLE_INT32_ALTERNATE;
1363   if (!_dbus_type_writer_write_basic (&sub,
1364                                       DBUS_TYPE_INT32,
1365                                       &v))
1366     {
1367       data_block_restore (block, &saved);
1368       return FALSE;
1369     }
1370
1371   v = SAMPLE_INT32;
1372   if (!_dbus_type_writer_write_basic (&sub,
1373                                       DBUS_TYPE_INT32,
1374                                       &v))
1375     {
1376       data_block_restore (block, &saved);
1377       return FALSE;
1378     }
1379
1380   v = SAMPLE_INT32;
1381   if (!_dbus_type_writer_write_basic (&sub,
1382                                       DBUS_TYPE_INT32,
1383                                       &v))
1384     {
1385       data_block_restore (block, &saved);
1386       return FALSE;
1387     }
1388   
1389   if (!_dbus_type_writer_unrecurse (writer, &sub))
1390     {
1391       data_block_restore (block, &saved);
1392       return FALSE;
1393     }
1394   
1395   return TRUE;
1396 }
1397
1398 static dbus_bool_t
1399 read_array_of_int32 (DataBlock      *block,
1400                      DBusTypeReader *reader)
1401 {
1402   dbus_int32_t v;
1403   DBusTypeReader sub;
1404
1405   check_expected_type (reader, DBUS_TYPE_ARRAY);
1406   
1407   _dbus_type_reader_recurse (reader, &sub);
1408
1409   check_expected_type (&sub, DBUS_TYPE_INT32);
1410   
1411   _dbus_type_reader_read_basic (&sub,
1412                                 (dbus_int32_t*) &v);
1413
1414   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1415
1416   NEXT_EXPECTING_TRUE (&sub);
1417   check_expected_type (&sub, DBUS_TYPE_INT32);
1418   
1419   _dbus_type_reader_read_basic (&sub,
1420                                 (dbus_int32_t*) &v);
1421
1422   _dbus_assert (v == SAMPLE_INT32);
1423
1424   NEXT_EXPECTING_TRUE (&sub);
1425   check_expected_type (&sub, DBUS_TYPE_INT32);
1426   
1427   _dbus_type_reader_read_basic (&sub,
1428                                 (dbus_int32_t*) &v);
1429
1430   _dbus_assert (v == SAMPLE_INT32);
1431
1432   NEXT_EXPECTING_FALSE (&sub);
1433   
1434   return TRUE;
1435 }
1436
1437
1438 static dbus_bool_t
1439 write_array_of_int32_empty (DataBlock      *block,
1440                             DBusTypeWriter *writer)
1441 {
1442   DataBlockState saved;
1443   DBusTypeWriter sub;
1444
1445   data_block_save (block, &saved);
1446   
1447   if (!_dbus_type_writer_recurse_array (writer,
1448                                         DBUS_TYPE_INT32_AS_STRING,
1449                                         &sub))
1450     return FALSE;
1451   
1452   if (!_dbus_type_writer_unrecurse (writer, &sub))
1453     {
1454       data_block_restore (block, &saved);
1455       return FALSE;
1456     }
1457   
1458   return TRUE;
1459 }
1460
1461 static dbus_bool_t
1462 read_array_of_int32_empty (DataBlock      *block,
1463                            DBusTypeReader *reader)
1464 {
1465   check_expected_type (reader, DBUS_TYPE_ARRAY);
1466
1467   /* We are iterating over values not types. Thus we can't recurse
1468    * into the array
1469    */
1470   _dbus_assert (_dbus_type_reader_array_is_empty (reader));
1471   
1472   return TRUE;
1473 }
1474
1475 static dbus_bool_t
1476 write_array_of_array_of_int32 (DataBlock      *block,
1477                                DBusTypeWriter *writer)
1478 {
1479   DataBlockState saved;
1480   DBusTypeWriter sub;
1481
1482   data_block_save (block, &saved);
1483   
1484   if (!_dbus_type_writer_recurse_array (writer,
1485                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1486                                         &sub))
1487     return FALSE;
1488
1489   if (!write_array_of_int32 (block, &sub))
1490     {
1491       data_block_restore (block, &saved);
1492       return FALSE;
1493     }
1494
1495   if (!write_array_of_int32 (block, &sub))
1496     {
1497       data_block_restore (block, &saved);
1498       return FALSE;
1499     }
1500
1501   if (!write_array_of_int32_empty (block, &sub))
1502     {
1503       data_block_restore (block, &saved);
1504       return FALSE;
1505     }
1506   
1507   if (!write_array_of_int32 (block, &sub))
1508     {
1509       data_block_restore (block, &saved);
1510       return FALSE;
1511     }
1512   
1513   if (!_dbus_type_writer_unrecurse (writer, &sub))
1514     {
1515       data_block_restore (block, &saved);
1516       return FALSE;
1517     }
1518   
1519   return TRUE;
1520 }
1521
1522 static dbus_bool_t
1523 read_array_of_array_of_int32 (DataBlock      *block,
1524                               DBusTypeReader *reader)
1525 {
1526   DBusTypeReader sub;
1527   
1528   check_expected_type (reader, DBUS_TYPE_ARRAY);
1529   
1530   _dbus_type_reader_recurse (reader, &sub);
1531
1532   if (!read_array_of_int32 (block, &sub))
1533     return FALSE;
1534
1535   NEXT_EXPECTING_TRUE (&sub);
1536   if (!read_array_of_int32 (block, &sub))
1537     return FALSE;
1538
1539   NEXT_EXPECTING_TRUE (&sub);
1540   if (!read_array_of_int32_empty (block, &sub))
1541     return FALSE;
1542   
1543   NEXT_EXPECTING_TRUE (&sub);
1544   if (!read_array_of_int32 (block, &sub))
1545     return FALSE;
1546
1547   NEXT_EXPECTING_FALSE (&sub);
1548   
1549   return TRUE;
1550 }
1551
1552
1553 static dbus_bool_t
1554 write_array_of_array_of_int32_empty (DataBlock      *block,
1555                                      DBusTypeWriter *writer)
1556 {
1557   DataBlockState saved;
1558   DBusTypeWriter sub;
1559
1560   data_block_save (block, &saved);
1561   
1562   if (!_dbus_type_writer_recurse_array (writer,
1563                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1564                                         &sub))
1565     return FALSE;
1566
1567   if (!_dbus_type_writer_unrecurse (writer, &sub))
1568     {
1569       data_block_restore (block, &saved);
1570       return FALSE;
1571     }
1572   
1573   return TRUE;
1574 }
1575
1576 static dbus_bool_t
1577 read_array_of_array_of_int32_empty (DataBlock      *block,
1578                                     DBusTypeReader *reader)
1579 {  
1580   check_expected_type (reader, DBUS_TYPE_ARRAY);
1581
1582   /* We are iterating over values, not types. Thus
1583    * we can't recurse in here.
1584    */
1585   
1586   _dbus_assert (_dbus_type_reader_array_is_empty (reader));
1587   
1588   return TRUE;
1589 }
1590
1591 static dbus_bool_t
1592 write_array_of_array_of_array_of_int32 (DataBlock      *block,
1593                                         DBusTypeWriter *writer)
1594 {
1595   DataBlockState saved;
1596   DBusTypeWriter sub;
1597
1598   data_block_save (block, &saved);
1599   
1600   if (!_dbus_type_writer_recurse_array (writer,
1601                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1602                                         &sub))
1603     return FALSE;
1604
1605   if (!write_array_of_array_of_int32 (block, &sub))
1606     {
1607       data_block_restore (block, &saved);
1608       return FALSE;
1609     }
1610
1611   if (!write_array_of_array_of_int32 (block, &sub))
1612     {
1613       data_block_restore (block, &saved);
1614       return FALSE;
1615     }
1616
1617   if (!write_array_of_array_of_int32_empty (block, &sub))
1618     {
1619       data_block_restore (block, &saved);
1620       return FALSE;
1621     }
1622   
1623   if (!_dbus_type_writer_unrecurse (writer, &sub))
1624     {
1625       data_block_restore (block, &saved);
1626       return FALSE;
1627     }
1628   
1629   return TRUE;
1630 }
1631
1632 static dbus_bool_t
1633 read_array_of_array_of_array_of_int32 (DataBlock      *block,
1634                                        DBusTypeReader *reader)
1635 {
1636   DBusTypeReader sub;
1637   
1638   check_expected_type (reader, DBUS_TYPE_ARRAY);
1639   
1640   _dbus_type_reader_recurse (reader, &sub);
1641
1642   if (!read_array_of_array_of_int32 (block, &sub))
1643     return FALSE;
1644
1645   NEXT_EXPECTING_TRUE (&sub);
1646   if (!read_array_of_array_of_int32 (block, &sub))
1647     return FALSE;
1648
1649   NEXT_EXPECTING_TRUE (&sub);
1650   if (!read_array_of_array_of_int32_empty (block, &sub))
1651     return FALSE;
1652
1653   NEXT_EXPECTING_FALSE (&sub);
1654   
1655   return TRUE;
1656 }
1657
1658 static dbus_bool_t
1659 write_struct_of_array_of_int32 (DataBlock      *block,
1660                                 DBusTypeWriter *writer)
1661 {
1662   DataBlockState saved;
1663   DBusTypeWriter sub;
1664
1665   data_block_save (block, &saved);
1666   
1667   if (!_dbus_type_writer_recurse (writer,
1668                                   DBUS_TYPE_STRUCT,
1669                                   &sub))
1670     return FALSE;
1671
1672   if (!write_array_of_int32 (block, &sub))
1673     {
1674       data_block_restore (block, &saved);
1675       return FALSE;
1676     }
1677
1678   if (!write_array_of_int32_empty (block, &sub))
1679     {
1680       data_block_restore (block, &saved);
1681       return FALSE;
1682     }
1683       
1684   if (!_dbus_type_writer_unrecurse (writer, &sub))
1685     {
1686       data_block_restore (block, &saved);
1687       return FALSE;
1688     }
1689   
1690   return TRUE;
1691 }
1692
1693 static dbus_bool_t
1694 read_struct_of_array_of_int32 (DataBlock      *block,
1695                                DBusTypeReader *reader)
1696 {
1697   DBusTypeReader sub;
1698
1699   check_expected_type (reader, DBUS_TYPE_STRUCT);
1700   
1701   _dbus_type_reader_recurse (reader, &sub);
1702
1703   check_expected_type (&sub, DBUS_TYPE_ARRAY);
1704
1705   if (!read_array_of_int32 (block, &sub))
1706     return FALSE;
1707
1708   NEXT_EXPECTING_TRUE (&sub);
1709   if (!read_array_of_int32_empty (block, &sub))
1710     return FALSE;
1711   
1712   NEXT_EXPECTING_FALSE (&sub);
1713   
1714   return TRUE;
1715 }
1716
1717 static dbus_bool_t
1718 write_struct_of_struct_of_array_of_int32 (DataBlock      *block,
1719                                           DBusTypeWriter *writer)
1720 {
1721   DataBlockState saved;
1722   DBusTypeWriter sub;
1723
1724   data_block_save (block, &saved);
1725   
1726   if (!_dbus_type_writer_recurse (writer,
1727                                   DBUS_TYPE_STRUCT,
1728                                   &sub))
1729     return FALSE;
1730
1731   if (!write_struct_of_array_of_int32 (block, &sub))
1732     {
1733       data_block_restore (block, &saved);
1734       return FALSE;
1735     }
1736   if (!write_struct_of_array_of_int32 (block, &sub))
1737     {
1738       data_block_restore (block, &saved);
1739       return FALSE;
1740     }
1741   if (!write_struct_of_array_of_int32 (block, &sub))
1742     {
1743       data_block_restore (block, &saved);
1744       return FALSE;
1745     }
1746
1747   if (!_dbus_type_writer_unrecurse (writer, &sub))
1748     {
1749       data_block_restore (block, &saved);
1750       return FALSE;
1751     }
1752   
1753   return TRUE;
1754 }
1755
1756 static dbus_bool_t
1757 read_struct_of_struct_of_array_of_int32 (DataBlock      *block,
1758                                          DBusTypeReader *reader)
1759 {
1760   DBusTypeReader sub;
1761   
1762   check_expected_type (reader, DBUS_TYPE_STRUCT);
1763   
1764   _dbus_type_reader_recurse (reader, &sub);
1765
1766   if (!read_struct_of_array_of_int32 (block, &sub))
1767     return FALSE;
1768
1769   NEXT_EXPECTING_TRUE (&sub);
1770   if (!read_struct_of_array_of_int32 (block, &sub))
1771     return FALSE;
1772
1773   NEXT_EXPECTING_TRUE (&sub);
1774   if (!read_struct_of_array_of_int32 (block, &sub))
1775     return FALSE;
1776   
1777   NEXT_EXPECTING_FALSE (&sub);
1778   
1779   return TRUE;
1780 }
1781
1782 static dbus_bool_t
1783 write_array_of_struct_of_int32 (DataBlock      *block,
1784                                 DBusTypeWriter *writer)
1785 {
1786   DataBlockState saved;
1787   DBusTypeWriter sub;
1788
1789   data_block_save (block, &saved);
1790
1791   if (!_dbus_type_writer_recurse_array (writer,
1792                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
1793                                         DBUS_TYPE_INT32_AS_STRING
1794                                         DBUS_TYPE_INT32_AS_STRING
1795                                         DBUS_STRUCT_END_CHAR_AS_STRING,
1796                                         &sub))
1797     return FALSE;
1798
1799   if (!write_struct_of_int32 (block, &sub))
1800     {
1801       data_block_restore (block, &saved);
1802       return FALSE;
1803     }
1804
1805   if (!write_struct_of_int32 (block, &sub))
1806     {
1807       data_block_restore (block, &saved);
1808       return FALSE;
1809     }
1810
1811   if (!write_struct_of_int32 (block, &sub))
1812     {
1813       data_block_restore (block, &saved);
1814       return FALSE;
1815     }
1816   
1817   if (!_dbus_type_writer_unrecurse (writer, &sub))
1818     {
1819       data_block_restore (block, &saved);
1820       return FALSE;
1821     }
1822   
1823   return TRUE;
1824 }
1825
1826 static dbus_bool_t
1827 read_array_of_struct_of_int32 (DataBlock      *block,
1828                                DBusTypeReader *reader)
1829 {
1830   DBusTypeReader sub;
1831
1832   check_expected_type (reader, DBUS_TYPE_ARRAY);
1833   
1834   _dbus_type_reader_recurse (reader, &sub);
1835
1836   check_expected_type (&sub, DBUS_TYPE_STRUCT);
1837
1838   if (!read_struct_of_int32 (block, &sub))
1839     return FALSE;
1840   
1841   NEXT_EXPECTING_TRUE (&sub);
1842
1843   if (!read_struct_of_int32 (block, &sub))
1844     return FALSE;
1845   
1846   NEXT_EXPECTING_TRUE (&sub);
1847
1848   if (!read_struct_of_int32 (block, &sub))
1849     return FALSE;
1850   
1851   NEXT_EXPECTING_FALSE (&sub);
1852   
1853   return TRUE;
1854 }
1855
1856
1857 static dbus_bool_t
1858 write_array_of_array_of_struct_of_int32 (DataBlock      *block,
1859                                          DBusTypeWriter *writer)
1860 {
1861   DataBlockState saved;
1862   DBusTypeWriter sub;
1863
1864   data_block_save (block, &saved);
1865
1866   if (!_dbus_type_writer_recurse_array (writer,
1867                                         DBUS_TYPE_ARRAY_AS_STRING
1868                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
1869                                         DBUS_TYPE_INT32_AS_STRING
1870                                         DBUS_TYPE_INT32_AS_STRING
1871                                         DBUS_STRUCT_END_CHAR_AS_STRING,
1872                                         &sub))
1873     return FALSE;
1874
1875   if (!write_array_of_struct_of_int32 (block, &sub))
1876     {
1877       data_block_restore (block, &saved);
1878       return FALSE;
1879     }
1880
1881   if (!write_array_of_struct_of_int32 (block, &sub))
1882     {
1883       data_block_restore (block, &saved);
1884       return FALSE;
1885     }
1886
1887   if (!write_array_of_struct_of_int32 (block, &sub))
1888     {
1889       data_block_restore (block, &saved);
1890       return FALSE;
1891     }
1892   
1893   if (!_dbus_type_writer_unrecurse (writer, &sub))
1894     {
1895       data_block_restore (block, &saved);
1896       return FALSE;
1897     }
1898   
1899   return TRUE;
1900 }
1901
1902 static dbus_bool_t
1903 read_array_of_array_of_struct_of_int32 (DataBlock      *block,
1904                                         DBusTypeReader *reader)
1905 {
1906   DBusTypeReader sub;
1907
1908   check_expected_type (reader, DBUS_TYPE_ARRAY);
1909   
1910   _dbus_type_reader_recurse (reader, &sub);
1911
1912   check_expected_type (&sub, DBUS_TYPE_ARRAY);
1913
1914   if (!read_array_of_struct_of_int32 (block, &sub))
1915     return FALSE;
1916   
1917   NEXT_EXPECTING_TRUE (&sub);
1918
1919   if (!read_array_of_struct_of_int32 (block, &sub))
1920     return FALSE;
1921   
1922   NEXT_EXPECTING_TRUE (&sub);
1923
1924   if (!read_array_of_struct_of_int32 (block, &sub))
1925     return FALSE;
1926   
1927   NEXT_EXPECTING_FALSE (&sub);
1928   
1929   return TRUE;
1930 }
1931
1932 static dbus_bool_t
1933 write_struct_of_array_of_struct_of_int32 (DataBlock      *block,
1934                                           DBusTypeWriter *writer)
1935 {
1936   DataBlockState saved;
1937   DBusTypeWriter sub;
1938
1939   data_block_save (block, &saved);
1940   
1941   if (!_dbus_type_writer_recurse (writer,
1942                                   DBUS_TYPE_STRUCT,
1943                                   &sub))
1944     return FALSE;
1945
1946   if (!write_array_of_struct_of_int32 (block, &sub))
1947     {
1948       data_block_restore (block, &saved);
1949       return FALSE;
1950     }
1951   if (!write_array_of_struct_of_int32 (block, &sub))
1952     {
1953       data_block_restore (block, &saved);
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 (!_dbus_type_writer_unrecurse (writer, &sub))
1963     {
1964       data_block_restore (block, &saved);
1965       return FALSE;
1966     }
1967   
1968   return TRUE;
1969 }
1970
1971 static dbus_bool_t
1972 read_struct_of_array_of_struct_of_int32 (DataBlock      *block,
1973                                          DBusTypeReader *reader)
1974 {
1975   DBusTypeReader sub;
1976   
1977   check_expected_type (reader, DBUS_TYPE_STRUCT);
1978   
1979   _dbus_type_reader_recurse (reader, &sub);
1980   
1981   if (!read_array_of_struct_of_int32 (block, &sub))
1982     return FALSE;
1983
1984   NEXT_EXPECTING_TRUE (&sub);
1985   if (!read_array_of_struct_of_int32 (block, &sub))
1986     return FALSE;
1987
1988   NEXT_EXPECTING_TRUE (&sub);
1989   if (!read_array_of_struct_of_int32 (block, &sub))
1990     return FALSE;
1991   
1992   NEXT_EXPECTING_FALSE (&sub);
1993   
1994   return TRUE;
1995 }
1996
1997 static dbus_bool_t
1998 write_array_of_struct_of_array_of_int32 (DataBlock      *block,
1999                                          DBusTypeWriter *writer)
2000 {
2001   DataBlockState saved;
2002   DBusTypeWriter sub;
2003
2004   data_block_save (block, &saved);
2005
2006   if (!_dbus_type_writer_recurse_array (writer,
2007                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2008                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING
2009                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING
2010                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2011                                         &sub))
2012     return FALSE;
2013
2014   if (!write_struct_of_array_of_int32 (block, &sub))
2015     {
2016       data_block_restore (block, &saved);
2017       return FALSE;
2018     }
2019
2020   if (!write_struct_of_array_of_int32 (block, &sub))
2021     {
2022       data_block_restore (block, &saved);
2023       return FALSE;
2024     }
2025
2026   if (!write_struct_of_array_of_int32 (block, &sub))
2027     {
2028       data_block_restore (block, &saved);
2029       return FALSE;
2030     }
2031   
2032   if (!_dbus_type_writer_unrecurse (writer, &sub))
2033     {
2034       data_block_restore (block, &saved);
2035       return FALSE;
2036     }
2037   
2038   return TRUE;
2039 }
2040
2041 static dbus_bool_t
2042 read_array_of_struct_of_array_of_int32 (DataBlock      *block,
2043                                         DBusTypeReader *reader)
2044 {
2045   DBusTypeReader sub;
2046
2047   check_expected_type (reader, DBUS_TYPE_ARRAY);
2048   
2049   _dbus_type_reader_recurse (reader, &sub);
2050
2051   check_expected_type (&sub, DBUS_TYPE_STRUCT);
2052
2053   if (!read_struct_of_array_of_int32 (block, &sub))
2054     return FALSE;
2055   
2056   NEXT_EXPECTING_TRUE (&sub);
2057
2058   if (!read_struct_of_array_of_int32 (block, &sub))
2059     return FALSE;
2060   
2061   NEXT_EXPECTING_TRUE (&sub);
2062
2063   if (!read_struct_of_array_of_int32 (block, &sub))
2064     return FALSE;
2065   
2066   NEXT_EXPECTING_FALSE (&sub);
2067   
2068   return TRUE;
2069 }
2070
2071 typedef enum {
2072   ITEM_INVALID = -1,
2073
2074   ITEM_INT32 = 0,
2075
2076   ITEM_STRUCT_OF_INT32,
2077   ITEM_STRUCT_OF_STRUCTS,
2078   ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
2079
2080   ITEM_ARRAY_OF_INT32,
2081   ITEM_ARRAY_OF_INT32_EMPTY,
2082   ITEM_ARRAY_OF_ARRAY_OF_INT32,
2083   ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
2084   ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
2085
2086   ITEM_STRUCT_OF_ARRAY_OF_INT32,
2087   ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32,
2088
2089   ITEM_ARRAY_OF_STRUCT_OF_INT32,
2090   ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32,
2091
2092   ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32,
2093   ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32,
2094
2095   ITEM_LAST
2096 } WhichItem;
2097
2098
2099 typedef dbus_bool_t (* WriteItemFunc) (DataBlock      *block,
2100                                        DBusTypeWriter *writer);
2101 typedef dbus_bool_t (* ReadItemFunc)  (DataBlock      *block,
2102                                        DBusTypeReader *reader);
2103
2104 typedef struct
2105 {
2106   const char *desc;
2107   WhichItem which;
2108   WriteItemFunc write_item_func;
2109   ReadItemFunc read_item_func;
2110 } CheckMarshalItem;
2111
2112 static CheckMarshalItem items[] = {
2113   { "int32",
2114     ITEM_INT32, write_int32, read_int32 },
2115   { "struct with two int32",
2116     ITEM_STRUCT_OF_INT32, write_struct_of_int32, read_struct_of_int32 },
2117   { "struct with three structs of two int32",
2118     ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
2119   { "struct of two structs of three structs of two int32",
2120     ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
2121     write_struct_of_structs_of_structs,
2122     read_struct_of_structs_of_structs },
2123   { "array of int32",
2124     ITEM_ARRAY_OF_INT32, write_array_of_int32, read_array_of_int32 },
2125   { "empty array of int32",
2126     ITEM_ARRAY_OF_INT32_EMPTY, write_array_of_int32_empty, read_array_of_int32_empty },
2127   { "array of array of int32",
2128     ITEM_ARRAY_OF_ARRAY_OF_INT32,
2129     write_array_of_array_of_int32, read_array_of_array_of_int32 },
2130   { "empty array of array of int32",
2131     ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
2132     write_array_of_array_of_int32_empty, read_array_of_array_of_int32_empty },
2133   { "array of array of array of int32",
2134     ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
2135     write_array_of_array_of_array_of_int32, read_array_of_array_of_array_of_int32 },
2136   { "struct of array of int32",
2137     ITEM_STRUCT_OF_ARRAY_OF_INT32, write_struct_of_array_of_int32, read_struct_of_array_of_int32 },
2138   { "struct of struct of array of int32",
2139     ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32,
2140     write_struct_of_struct_of_array_of_int32, read_struct_of_struct_of_array_of_int32 },
2141   { "array of struct of int32",
2142     ITEM_ARRAY_OF_STRUCT_OF_INT32, write_array_of_struct_of_int32, read_array_of_struct_of_int32 },
2143   { "array of array of struct of int32",
2144     ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32,
2145     write_array_of_array_of_struct_of_int32, read_array_of_array_of_struct_of_int32 },
2146
2147   { "struct of array of struct of int32",
2148     ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32,
2149     write_struct_of_array_of_struct_of_int32, read_struct_of_array_of_struct_of_int32 },
2150   { "array of struct of array of int32",
2151     ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32,
2152     write_array_of_struct_of_array_of_int32, read_array_of_struct_of_array_of_int32 },
2153 };
2154
2155 typedef struct
2156 {
2157   /* Array of items from the above items[]; -1 terminated */
2158   int items[20];
2159 } TestRun;
2160
2161 static TestRun runs[] = {
2162   { { ITEM_INVALID } },
2163
2164   /* INT32 */
2165   { { ITEM_INT32, ITEM_INVALID } },
2166   { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
2167   { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
2168
2169   /* STRUCT_OF_INT32 */
2170   { { ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2171   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2172   { { ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2173   { { ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2174   { { ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_OF_INT32, ITEM_INVALID } },
2175
2176   /* STRUCT_OF_STRUCTS */
2177   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2178   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2179   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2180   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2181   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2182   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
2183
2184   /* STRUCT_OF_STRUCTS_OF_STRUCTS */
2185   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2186   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2187   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2188   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2189   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2190   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2191
2192   /* ARRAY_OF_INT32 */
2193   { { ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2194   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2195   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2196   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2197   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2198   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2199   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2200   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2201   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2202   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
2203
2204   /* ARRAY_OF_ARRAY_OF_INT32 */
2205   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2206   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2207   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2208   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2209   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2210   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2211   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2212   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2213   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2214   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2215
2216   /* ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32 */
2217   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2218   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2219   { { 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 } },
2220   { { 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 } },
2221   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
2222   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2223   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2224   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
2225   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2226   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2227
2228   /* STRUCT_OF_ARRAY_OF_INT32 */
2229   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2230   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2231   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2232   { { ITEM_STRUCT_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2233   { { ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2234   { { ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2235
2236   /* STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32 */
2237   { { ITEM_STRUCT_OF_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2238   
2239   /* ARRAY_OF_STRUCT_OF_INT32 */
2240   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2241   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2242   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2243   { { ITEM_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2244   { { ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2245   { { ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2246
2247   /* ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32 */
2248   { { ITEM_ARRAY_OF_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2249   
2250   /* STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32 */
2251   { { ITEM_STRUCT_OF_ARRAY_OF_STRUCT_OF_INT32, ITEM_INVALID } },
2252   
2253   /* ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32 */
2254   { { ITEM_ARRAY_OF_STRUCT_OF_ARRAY_OF_INT32, ITEM_INVALID } },
2255   
2256 };
2257
2258 static dbus_bool_t
2259 perform_one_run (DataBlock *block,
2260                  int        byte_order,
2261                  TestRun   *run)
2262 {
2263   DBusTypeReader reader;
2264   DBusTypeWriter writer;
2265   int i;
2266   DataBlockState saved;
2267   dbus_bool_t retval;
2268
2269   retval = FALSE;
2270
2271   {
2272     _dbus_verbose ("run byteorder %s items ",
2273                    byte_order == DBUS_LITTLE_ENDIAN ? "little" : "big");
2274     i = 0;
2275     while (run->items[i] != ITEM_INVALID)
2276       {
2277         CheckMarshalItem *item = &items[run->items[i]];
2278         
2279         _dbus_verbose ("%s ", item->desc);
2280         ++i;
2281       }
2282     _dbus_verbose (" = %d items\n", i);
2283   }
2284   
2285   data_block_save (block, &saved);
2286   
2287   data_block_init_reader_writer (block, 
2288                                  byte_order,
2289                                  &reader, &writer);
2290
2291   i = 0;
2292   while (run->items[i] != ITEM_INVALID)
2293     {
2294       CheckMarshalItem *item = &items[run->items[i]];
2295
2296       _dbus_verbose (">>writing %s\n", item->desc);
2297       
2298       if (!(* item->write_item_func) (block, &writer))
2299         goto out;
2300       ++i;
2301     }
2302
2303   i = 0;
2304   while (run->items[i] != ITEM_INVALID)
2305     {
2306       CheckMarshalItem *item = &items[run->items[i]];
2307
2308       _dbus_verbose (">>data for reading %s\n", item->desc);
2309       
2310       _dbus_verbose_bytes_of_string (reader.type_str, 0,
2311                                      _dbus_string_get_length (reader.type_str));
2312       _dbus_verbose_bytes_of_string (reader.value_str, 0,
2313                                      _dbus_string_get_length (reader.value_str));
2314       
2315       _dbus_verbose (">>reading %s\n", item->desc);
2316       
2317       if (!(* item->read_item_func) (block, &reader))
2318         goto out;
2319
2320       _dbus_type_reader_next (&reader);
2321       
2322       ++i;
2323     }
2324   
2325   retval = TRUE;
2326   
2327  out:
2328   data_block_restore (block, &saved);
2329   return retval;
2330 }
2331
2332 static dbus_bool_t
2333 perform_all_runs (int byte_order,
2334                   int initial_offset)
2335 {
2336   int i;
2337   DataBlock block;
2338   dbus_bool_t retval;
2339
2340   retval = FALSE;
2341   
2342   if (!data_block_init (&block))
2343     return FALSE;
2344
2345   if (!_dbus_string_lengthen (&block.signature, initial_offset))
2346     goto out;
2347   
2348   if (!_dbus_string_lengthen (&block.body, initial_offset))
2349     goto out;
2350   
2351   i = 0;
2352   while (i < _DBUS_N_ELEMENTS (runs))
2353     {
2354       if (!perform_one_run (&block, byte_order, &runs[i]))
2355         goto out;
2356       
2357       ++i;
2358     }
2359
2360   retval = TRUE;
2361   
2362  out:
2363   data_block_free (&block);
2364   
2365   return retval;
2366 }
2367
2368 static dbus_bool_t
2369 perform_all_items (int byte_order,
2370                    int initial_offset)
2371 {
2372   int i;
2373   DataBlock block;
2374   dbus_bool_t retval;
2375   TestRun run;
2376
2377   retval = FALSE;
2378   
2379   if (!data_block_init (&block))
2380     return FALSE;
2381
2382
2383   if (!_dbus_string_lengthen (&block.signature, initial_offset))
2384     goto out;
2385   
2386   if (!_dbus_string_lengthen (&block.body, initial_offset))
2387     goto out;
2388
2389   /* Create a run containing all the items */
2390   i = 0;
2391   while (i < _DBUS_N_ELEMENTS (items))
2392     {
2393       _dbus_assert (i == items[i].which);
2394       
2395       run.items[i] = items[i].which;
2396       
2397       ++i;
2398     }
2399   
2400   run.items[i] = ITEM_INVALID;
2401
2402   if (!perform_one_run (&block, byte_order, &run))
2403     goto out;  
2404   
2405   retval = TRUE;
2406   
2407  out:
2408   data_block_free (&block);
2409   
2410   return retval;
2411 }
2412
2413 static dbus_bool_t
2414 recursive_marshal_test_iteration (void *data)
2415 {
2416   int i;
2417
2418   i = 0;
2419   while (i < 18)
2420     {
2421       if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
2422         return FALSE;
2423       if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
2424         return FALSE;
2425       if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
2426         return FALSE;
2427       if (!perform_all_items (DBUS_BIG_ENDIAN, i))
2428         return FALSE;
2429       
2430       ++i;
2431     }
2432
2433   return TRUE;
2434 }
2435
2436 dbus_bool_t _dbus_marshal_recursive_test (void);
2437
2438 dbus_bool_t
2439 _dbus_marshal_recursive_test (void)
2440 {
2441   _dbus_test_oom_handling ("recursive marshaling",
2442                            recursive_marshal_test_iteration,
2443                            NULL);  
2444   
2445   return TRUE;
2446 }
2447
2448 #if 1
2449 int
2450 main (int argc, char **argv)
2451 {
2452   _dbus_marshal_recursive_test ();
2453
2454   return 0;
2455 }
2456 #endif /* main() */
2457
2458 #endif /* DBUS_BUILD_TESTS */