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