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