sync busted marshaling work in progress
[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 int
131 _dbus_type_reader_get_array_length (DBusTypeReader *reader)
132 {
133   /* FIXME if this is in number of elements I don't know how to compute it
134    * since we only have bytes and elements are variable-length
135    */
136 }
137
138 void
139 _dbus_type_reader_read_basic (DBusTypeReader    *reader,
140                               void              *value)
141 {
142   if (reader->container_type == DBUS_TYPE_INVALID ||
143       reader->container_type == DBUS_TYPE_STRUCT ||
144       reader->container_type == DBUS_TYPE_ARRAY)
145     {
146       int t;
147       int next;
148       
149       t = _dbus_type_reader_get_current_type (reader);
150
151       next = reader->value_pos;
152       _dbus_demarshal_basic_type (reader->value_str,
153                                   t, value,
154                                   reader->byte_order,
155                                   &next);
156
157
158       _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
159                      reader, reader->type_pos, reader->value_pos, next,
160                      _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
161       
162       _dbus_verbose_bytes_of_string (reader->value_str,
163                                      reader->value_pos,
164                                      MIN (16,
165                                           _dbus_string_get_length (reader->value_str) - reader->value_pos));
166     }
167   else
168     {
169       _dbus_assert_not_reached ("reader->container_type should not be set to this");
170     }
171 }
172
173 dbus_bool_t
174 _dbus_type_reader_read_array_of_basic (DBusTypeReader    *reader,
175                                        int                type,
176                                        void             **array,
177                                        int               *array_len)
178 {
179   
180   
181 }
182
183 /**
184  * Initialize a new reader pointing to the first type and
185  * corresponding value that's a child of the current container. It's
186  * an error to call this if the current type is a non-container.
187  *
188  * @param reader the reader
189  * @param sub a reader to init pointing to the first child
190  */
191 void
192 _dbus_type_reader_recurse (DBusTypeReader *reader,
193                            DBusTypeReader *sub)
194 {
195   int t;
196
197   /* FIXME are we recursing over the type signature or over the values.
198    * Arrays don't necessarily have values for each element of the type
199    * signature. Thus we get a mismatch where we need to "bail out" and
200    * return the signature of each element, but can't return an element
201    * or recurse into the element signature. Not sure how to handle this;
202    * maybe think about how we will handle variant types and do something
203    * similar since they also have the idea of a signature for the whole
204    * sub-item?
205    */
206   
207   t = first_type_in_signature (reader->type_str, reader->type_pos);
208   
209   /* point subreader at the same place as reader */
210   _dbus_type_reader_init (sub,
211                           reader->byte_order,
212                           reader->type_str,
213                           reader->type_pos,
214                           reader->value_str,
215                           reader->value_pos);
216
217   if (t == DBUS_TYPE_STRUCT)
218     {
219       sub->container_type = DBUS_TYPE_STRUCT;
220       
221       sub->type_pos += 1;
222
223       /* struct has 8 byte alignment */
224       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
225
226       sub->u.strct.finished = FALSE;
227     }
228   else if (t == DBUS_TYPE_ARRAY)
229     {
230       dbus_uint32_t array_len;
231       int alignment;
232
233       sub->container_type = DBUS_TYPE_ARRAY;
234       
235       /* point type_pos at the array element type */
236       sub->type_pos += 1;
237
238       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
239       
240       _dbus_demarshal_basic_type (sub->value_str,
241                                   DBUS_TYPE_UINT32,
242                                   &array_len,
243                                   sub->byte_order,
244                                   &sub->value_pos);
245       
246       sub->u.array.len = array_len;
247       
248       alignment = element_type_get_alignment (sub->type_str,
249                                               sub->type_pos);
250       
251       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
252
253       sub->u.array.element_type = first_type_in_signature (sub->type_str,
254                                                            sub->type_pos);
255       sub->u.array.start_pos = sub->value_pos;
256
257       _dbus_verbose ("    type reader %p array start = %d array len = %d array element type = %s\n",
258                      reader,
259                      sub->u.array.start_pos,
260                      sub->u.array.len,
261                      _dbus_type_to_string (sub->u.array.element_type));
262     }
263   else
264     {
265       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
266       if (t == DBUS_TYPE_INVALID)
267         _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
268       
269       _dbus_assert_not_reached ("don't yet handle recursing into this type");
270     }
271
272   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
273                  sub, sub->type_pos, sub->value_pos,
274                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
275 }
276
277 static void
278 skip_one_complete_type (const DBusString *type_str,
279                         int              *type_pos)
280 {
281   while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
282     *type_pos += 1;
283
284   if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
285     {
286       int depth;
287       depth = 1;
288       *type_pos += 1;
289       while (depth > 0)
290         {
291           switch (_dbus_string_get_byte (type_str, *type_pos))
292             {
293             case DBUS_STRUCT_BEGIN_CHAR:
294               depth += 1;
295               break;
296             case DBUS_STRUCT_END_CHAR:
297               depth -= 1;
298               break;
299             case DBUS_TYPE_INVALID:
300               _dbus_assert_not_reached ("unbalanced parens in signature");
301               break;
302             }
303           *type_pos += 1;
304         }
305     }
306   else
307     *type_pos += 1;
308 }
309
310 /**
311  * Skip to the next value on this "level". e.g. the next field in a
312  * struct, the next value in an array, the next key or value in a
313  * dict. Returns FALSE at the end of the current container.
314  *
315  * @param reader the reader
316  * @returns FALSE if nothing more to read at or below this level
317  */
318 dbus_bool_t
319 _dbus_type_reader_next (DBusTypeReader *reader)
320 {
321   int t;
322   
323   t = _dbus_type_reader_get_current_type (reader);
324   
325   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
326                  reader, reader->type_pos, reader->value_pos,
327                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
328                  _dbus_type_to_string (t));
329
330   if (t == DBUS_TYPE_INVALID)
331     return FALSE;
332   
333   if (reader->container_type == DBUS_TYPE_INVALID ||
334       reader->container_type == DBUS_TYPE_STRUCT)
335     {
336       switch (t)
337         {
338         case DBUS_TYPE_STRUCT:
339         case DBUS_TYPE_ARRAY:
340           /* Scan forward over the entire container contents */
341           /* FIXME this is super slow for arrays. We need to special
342            * case skipping all the elements at once instead of scanning.
343            */
344           {
345             DBusTypeReader sub;
346
347             /* Recurse into the struct */
348             _dbus_type_reader_recurse (reader, &sub);
349
350             /* Skip everything in this subreader */
351             while (_dbus_type_reader_next (&sub))
352               {
353                 /* nothing */;
354               }
355
356             /* Now we are at the end of this container */
357             reader->type_pos = sub.type_pos;
358             reader->value_pos = sub.value_pos;
359           }
360           break;
361
362         default:
363           _dbus_marshal_skip_basic_type (reader->value_str,
364                                          t, reader->byte_order,
365                                          &reader->value_pos);
366           reader->type_pos += 1;
367           break;
368         }
369
370       /* for STRUCT containers we return FALSE at the end of the struct,
371        * for INVALID we return FALSE at the end of the signature.
372        * In both cases we arrange for get_current_type() to return INVALID
373        * which is defined to happen iff we're at the end (no more next())
374        */
375       if (reader->container_type == DBUS_TYPE_STRUCT)
376         {
377           t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
378           if (t == DBUS_STRUCT_END_CHAR)
379             {
380               reader->type_pos += 1;
381               reader->u.strct.finished = TRUE;
382             }
383         }
384     }
385   else if (reader->container_type == DBUS_TYPE_ARRAY)
386     {
387       /* Skip one array element */
388       int end_pos;
389
390       end_pos = reader->u.array.start_pos + reader->u.array.len;
391
392       _dbus_assert (reader->value_pos < end_pos);
393       _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
394
395       if (reader->u.array.element_type == DBUS_TYPE_ARRAY ||
396           reader->u.array.element_type == DBUS_TYPE_STRUCT)
397         {
398           DBusTypeReader sub;
399           
400           /* Recurse into the array element */
401           _dbus_type_reader_recurse (reader, &sub);
402
403             /* Skip everything in this element */
404           while (_dbus_type_reader_next (&sub))
405             {
406               /* nothing */;
407             }
408
409           /* Now we are at the end of this element */
410           reader->value_pos = sub.value_pos;
411         }
412       else
413         {
414           _dbus_marshal_skip_basic_type (reader->value_str,
415                                          t, reader->byte_order,
416                                          &reader->value_pos);
417         }
418
419       _dbus_assert (reader->value_pos <= end_pos);
420       
421       if (reader->value_pos == end_pos)
422         {
423           skip_one_complete_type (reader->type_str,
424                                   &reader->type_pos);
425         }
426     }
427   else
428     {
429       _dbus_assert_not_reached ("reader->container_type should not be set to this");
430     }
431   
432   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
433                  reader, reader->type_pos, reader->value_pos,
434                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
435                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
436   
437   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
438 }
439
440 void
441 _dbus_type_writer_init (DBusTypeWriter *writer,
442                         int             byte_order,
443                         DBusString     *type_str,
444                         int             type_pos,
445                         DBusString     *value_str,
446                         int             value_pos)
447 {
448   writer->byte_order = byte_order;
449   writer->type_str = type_str;
450   writer->type_pos = type_pos;
451   writer->value_str = value_str;
452   writer->value_pos = value_pos;
453   writer->container_type = DBUS_TYPE_INVALID;
454   writer->inside_array = FALSE;
455 }
456
457 static dbus_bool_t
458 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
459                                            int             type,
460                                            const void     *value)
461 {
462   int old_value_len;
463   int bytes_written;
464
465   old_value_len = _dbus_string_get_length (writer->value_str);
466         
467   if (!_dbus_marshal_basic_type (writer->value_str,
468                                  writer->value_pos,
469                                  type,
470                                  value,
471                                  writer->byte_order))
472     return FALSE;
473
474   bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
475   
476   writer->value_pos += bytes_written;
477
478   return TRUE;
479 }
480
481 dbus_bool_t
482 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
483                                int             type,
484                                const void     *value)
485 {
486   dbus_bool_t retval;
487   
488   /* First ensure that our type realloc will succeed */
489   if (!_dbus_string_alloc_space (writer->type_str, 1))
490     return FALSE;
491
492   retval = FALSE;
493
494   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
495     goto out;
496   
497   /* Now insert the type unless we're already covered by the array signature */
498   if (!writer->inside_array)
499     {
500       if (!_dbus_string_insert_byte (writer->type_str,
501                                      writer->type_pos,
502                                      type))
503         _dbus_assert_not_reached ("failed to insert byte after prealloc");
504       
505       writer->type_pos += 1;
506     }
507   
508   retval = TRUE;
509   
510  out:
511   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d inside_array = %d\n",
512                  writer, writer->type_pos, writer->value_pos, writer->inside_array);
513   
514   return retval;
515 }
516
517 dbus_bool_t
518 _dbus_type_writer_write_array (DBusTypeWriter *writer,
519                                int             type,
520                                const void     *array,
521                                int             array_len)
522 {
523
524
525 }
526
527 static void
528 writer_recurse_init_and_check (DBusTypeWriter *writer,
529                                int             container_type,
530                                const char     *array_element_type,
531                                DBusTypeWriter *sub)
532 {
533   _dbus_type_writer_init (sub,
534                           writer->byte_order,
535                           writer->type_str,
536                           writer->type_pos,
537                           writer->value_str,
538                           writer->value_pos);
539   
540   sub->container_type = container_type;
541
542   /* While inside an array, we never want to write to the type str.
543    * We are inside an array if we're currently recursing into one.
544    */
545   if (writer->inside_array || sub->container_type == DBUS_TYPE_ARRAY)
546     sub->inside_array = TRUE;
547   else
548     sub->inside_array = FALSE;
549
550   /* If our parent is an array, things are a little bit complicated.
551    *
552    * The parent must have a complete element type, such as
553    * "i" or "aai" or "(ii)" or "a(ii)". There can't be
554    * unclosed parens, or an "a" with no following type.
555    *
556    * To recurse, the only allowed operation is to recurse into the
557    * first type in the element type. So for "i" you can't recurse, for
558    * "ai" you can recurse into the array, for "(ii)" you can recurse
559    * into the struct.
560    *
561    * If you recurse into the array for "ai", then you must specify
562    * "i" for the element type of the array you recurse into.
563    * 
564    * While inside an array at any level, we need to avoid writing to
565    * type_str, since the type only appears once for the whole array,
566    * it does not appear for each array element.
567    */
568 #ifndef DBUS_DISABLE_CHECKS
569   if (writer->container_type == DBUS_TYPE_ARRAY)
570     {
571       if ((sub->container_type == DBUS_TYPE_STRUCT &&
572            writer->u.array.element_type[0] != DBUS_STRUCT_BEGIN_CHAR) ||
573           (sub->container_type != DBUS_TYPE_STRUCT &&
574            writer->u.array.element_type[0] != sub->container_type))
575         {
576           _dbus_warn ("Recursing into an array with element type %s not allowed with container type %s\n",
577                       writer->u.array.element_type, _dbus_type_to_string (sub->container_type));
578         }
579
580       if (sub->container_type == DBUS_TYPE_ARRAY)
581         {
582           DBusString parent_elements;
583           DBusString our_elements;
584
585           _dbus_assert (writer->u.array.element_type[0] == DBUS_TYPE_ARRAY);
586           
587           _dbus_string_init_const (&parent_elements, &writer->u.array.element_type[1]);
588           _dbus_string_init_const (&our_elements, array_element_type);
589
590           if (!_dbus_string_equal (&parent_elements, &our_elements))
591             {
592               _dbus_warn ("Parent array expects elements '%s' and we are writing an array of '%s'\n",
593                           writer->u.array.element_type,
594                           array_element_type);
595             }
596         }
597     }
598 #endif /* DBUS_DISABLE_CHECKS */
599
600   _dbus_verbose ("  type writer %p recurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
601                  writer, writer->type_pos, writer->value_pos, writer->inside_array,
602                  _dbus_type_to_string (writer->container_type));
603   _dbus_verbose ("  type writer %p new sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
604                  sub, sub->type_pos, sub->value_pos,
605                  sub->inside_array,
606                  _dbus_type_to_string (sub->container_type),
607                  array_element_type ? array_element_type : "n/a");
608 }
609
610 dbus_bool_t
611 _dbus_type_writer_recurse (DBusTypeWriter *writer,
612                            int             container_type,
613                            DBusTypeWriter *sub)
614 {
615   writer_recurse_init_and_check (writer, container_type, NULL, sub);
616   
617   switch (container_type)
618     {
619     case DBUS_TYPE_STRUCT:
620       {
621         if (!writer->inside_array)
622           {
623             /* Ensure that we'll be able to add alignment padding */
624             if (!_dbus_string_alloc_space (sub->value_str, 8))
625               return FALSE;
626             
627             if (!_dbus_string_insert_byte (sub->type_str,
628                                            sub->type_pos,
629                                            DBUS_STRUCT_BEGIN_CHAR))
630               return FALSE;
631
632             sub->type_pos += 1;
633           }
634
635         if (!_dbus_string_insert_bytes (sub->value_str,
636                                         sub->value_pos,
637                                         _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
638                                         '\0'))
639           _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
640         sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
641       }
642       break;
643     case DBUS_TYPE_ARRAY:
644       _dbus_assert_not_reached ("use recurse_array() for arrays");
645       break;
646     default:
647       _dbus_assert_not_reached ("container_type unhandled");
648       break;
649     }
650   
651   return TRUE;
652 }
653
654 dbus_bool_t
655 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
656                                  const char     *element_type,
657                                  DBusTypeWriter *sub)
658 {
659   int element_type_len;
660   DBusString element_type_str;
661   
662   writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, element_type, sub);
663
664   _dbus_string_init_const (&element_type_str, element_type);
665   element_type_len = _dbus_string_get_length (&element_type_str);
666
667   /* 4 bytes for the array length and 4 bytes possible padding */
668   if (!_dbus_string_alloc_space (sub->value_str, 8))
669     return FALSE;
670
671   if (!writer->inside_array)
672     {
673       /* alloc space for array typecode, element signature, possible 7
674        * bytes of padding
675        */
676       if (!_dbus_string_alloc_space (sub->type_str, 1 + element_type_len + 7))
677         return FALSE;
678     }
679       
680   if (!_dbus_string_copy_data (&element_type_str,
681                                &sub->u.array.element_type))
682     return FALSE;
683
684   if (!writer->inside_array)
685     {
686       if (!_dbus_string_insert_byte (sub->type_str,
687                                      sub->type_pos,
688                                      DBUS_TYPE_ARRAY))
689         _dbus_assert_not_reached ("should not have failed to insert array typecode");
690
691       sub->type_pos += 1;
692       
693       if (!_dbus_string_copy (&element_type_str, 0,
694                               sub->type_str, sub->type_pos))
695         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
696   
697       sub->type_pos += element_type_len;
698     }
699   
700   sub->u.array.len_pos = sub->value_pos;
701
702   {
703     dbus_uint32_t value = 0;
704     int alignment;
705     int aligned;
706     DBusString str;
707     
708     if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
709                                                     &value))
710       _dbus_assert_not_reached ("should not have failed to insert array len");
711
712     _dbus_string_init_const (&str, element_type);
713     alignment = element_type_get_alignment (&str, 0);
714
715     aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
716     if (aligned != sub->value_pos)
717       {
718         if (!_dbus_string_insert_bytes (sub->value_str,
719                                         sub->value_pos,
720                                         aligned - sub->value_pos,
721                                         '\0'))
722           _dbus_assert_not_reached ("should not have failed to insert alignment padding");
723
724         sub->value_pos = aligned;
725       }
726     sub->u.array.start_pos = sub->value_pos;
727   }
728
729   _dbus_assert (sub->u.array.start_pos == sub->value_pos);
730   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
731   
732   /* value_pos now points to the place for array data, and len_pos to the length */
733
734   return TRUE;
735 }
736
737 dbus_bool_t
738 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
739                              DBusTypeWriter *sub)
740 {
741   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
742
743   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
744                  writer, writer->type_pos, writer->value_pos, writer->inside_array,
745                  _dbus_type_to_string (writer->container_type));
746   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
747                  sub, sub->type_pos, sub->value_pos,
748                  sub->inside_array,
749                  _dbus_type_to_string (sub->container_type),
750                  sub->container_type == DBUS_TYPE_ARRAY ?
751                  sub->u.array.element_type : "n/a");
752   
753   if (sub->container_type == DBUS_TYPE_STRUCT)
754     {
755       if (!sub->inside_array)
756         {
757           if (!_dbus_string_insert_byte (sub->type_str,
758                                          sub->type_pos, 
759                                          DBUS_STRUCT_END_CHAR))
760             return FALSE;
761           sub->type_pos += 1;
762         }
763     }
764   else if (sub->container_type == DBUS_TYPE_ARRAY)
765     {
766       dbus_uint32_t len;
767       
768       dbus_free (sub->u.array.element_type);
769       sub->u.array.element_type = NULL;
770
771       /* Set the array length */
772       len = sub->value_pos - sub->u.array.start_pos;
773       _dbus_marshal_set_uint32 (sub->value_str,
774                                 sub->byte_order,
775                                 sub->u.array.len_pos,
776                                 len);
777       _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
778                      len, sub->u.array.len_pos);
779     }
780
781   /* Jump the parent writer to the new location */
782   writer->type_pos = sub->type_pos;
783   writer->value_pos = sub->value_pos;
784   
785   return TRUE;
786 }
787
788 /** @} */ /* end of DBusMarshal group */
789
790 #ifdef DBUS_BUILD_TESTS
791 #include "dbus-test.h"
792 #include <stdio.h>
793 #include <stdlib.h>
794
795 typedef struct
796 {
797   DBusString signature;
798   DBusString body;
799 } DataBlock;
800
801 typedef struct
802 {
803   int saved_sig_len;
804   int saved_body_len;
805 } DataBlockState;
806
807 static dbus_bool_t
808 data_block_init (DataBlock *block)
809 {
810   if (!_dbus_string_init (&block->signature))
811     return FALSE;
812
813   if (!_dbus_string_init (&block->body))
814     {
815       _dbus_string_free (&block->signature);
816       return FALSE;
817     }
818   
819   return TRUE;
820 }
821
822 static void
823 data_block_free (DataBlock *block)
824 {
825   _dbus_string_free (&block->signature);
826   _dbus_string_free (&block->body);
827 }
828
829 static void
830 data_block_save (DataBlock      *block,
831                  DataBlockState *state)
832 {
833   state->saved_sig_len = _dbus_string_get_length (&block->signature);
834   state->saved_body_len = _dbus_string_get_length (&block->body);
835 }
836
837 static void
838 data_block_restore (DataBlock      *block,
839                     DataBlockState *state)
840 {
841   /* These set_length should be shortening things so should always work */
842   
843   if (!_dbus_string_set_length (&block->signature,
844                                 state->saved_sig_len))
845     _dbus_assert_not_reached ("could not restore signature length");
846   
847   if (!_dbus_string_set_length (&block->body,
848                                 state->saved_body_len))
849     _dbus_assert_not_reached ("could not restore body length");
850 }
851
852 static void
853 data_block_init_reader_writer (DataBlock      *block,
854                                int             byte_order,
855                                DBusTypeReader *reader,
856                                DBusTypeWriter *writer)
857 {
858   _dbus_type_reader_init (reader,
859                           byte_order,
860                           &block->signature,
861                           _dbus_string_get_length (&block->signature),
862                           &block->body,
863                           _dbus_string_get_length (&block->body));
864   
865   _dbus_type_writer_init (writer,
866                           byte_order,
867                           &block->signature,
868                           _dbus_string_get_length (&block->signature),
869                           &block->body,
870                           _dbus_string_get_length (&block->body));
871 }
872
873 #define SAMPLE_INT32           12345678
874 #define SAMPLE_INT32_ALTERNATE 53781429
875 static dbus_bool_t
876 write_int32 (DataBlock      *block,
877              DBusTypeWriter *writer)
878 {
879   dbus_int32_t v = SAMPLE_INT32;
880
881   return _dbus_type_writer_write_basic (writer,
882                                         DBUS_TYPE_INT32,
883                                         &v);
884 }
885
886 static void
887 check_expected_type (DBusTypeReader *reader,
888                      int             expected)
889 {
890   int t;
891
892   t = _dbus_type_reader_get_current_type (reader);
893   
894   if (t != expected)
895     {
896       _dbus_warn ("Read type %s while expecting %s\n",
897                   _dbus_type_to_string (t),
898                   _dbus_type_to_string (expected));
899
900       _dbus_verbose_bytes_of_string (reader->type_str, 0,
901                                      _dbus_string_get_length (reader->type_str));
902       _dbus_verbose_bytes_of_string (reader->value_str, 0,
903                                      _dbus_string_get_length (reader->value_str));
904       
905       exit (1);
906     }
907 }
908
909 static dbus_bool_t
910 read_int32 (DataBlock      *block,
911             DBusTypeReader *reader)
912 {
913   dbus_int32_t v;
914
915   check_expected_type (reader, DBUS_TYPE_INT32);
916   
917   _dbus_type_reader_read_basic (reader,
918                                 (dbus_int32_t*) &v);
919
920   _dbus_assert (v == SAMPLE_INT32);
921
922   return TRUE;
923 }
924
925 static dbus_bool_t
926 write_struct_with_int32s (DataBlock      *block,
927                           DBusTypeWriter *writer)
928 {
929   dbus_int32_t v;
930   DataBlockState saved;
931   DBusTypeWriter sub;
932
933   data_block_save (block, &saved);
934   
935   if (!_dbus_type_writer_recurse (writer,
936                                   DBUS_TYPE_STRUCT,
937                                   &sub))
938     return FALSE;
939
940   v = SAMPLE_INT32;
941   if (!_dbus_type_writer_write_basic (&sub,
942                                       DBUS_TYPE_INT32,
943                                       &v))
944     {
945       data_block_restore (block, &saved);
946       return FALSE;
947     }
948
949   v = SAMPLE_INT32_ALTERNATE;
950   if (!_dbus_type_writer_write_basic (&sub,
951                                       DBUS_TYPE_INT32,
952                                       &v))
953     {
954       data_block_restore (block, &saved);
955       return FALSE;
956     }
957
958   if (!_dbus_type_writer_unrecurse (writer, &sub))
959     {
960       data_block_restore (block, &saved);
961       return FALSE;
962     }
963   
964   return TRUE;
965 }
966
967 static dbus_bool_t
968 read_struct_with_int32s (DataBlock      *block,
969                          DBusTypeReader *reader)
970 {
971   dbus_int32_t v;
972   DBusTypeReader sub;
973
974   check_expected_type (reader, DBUS_TYPE_STRUCT);
975   
976   _dbus_type_reader_recurse (reader, &sub);
977
978   check_expected_type (&sub, DBUS_TYPE_INT32);
979   
980   _dbus_type_reader_read_basic (&sub,
981                                 (dbus_int32_t*) &v);
982
983   _dbus_assert (v == SAMPLE_INT32);
984
985   _dbus_type_reader_next (&sub);
986   check_expected_type (&sub, DBUS_TYPE_INT32);
987   
988   _dbus_type_reader_read_basic (&sub,
989                                 (dbus_int32_t*) &v);
990
991   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
992   
993   return TRUE;
994 }
995
996 static dbus_bool_t
997 write_struct_of_structs (DataBlock      *block,
998                          DBusTypeWriter *writer)
999 {
1000   DataBlockState saved;
1001   DBusTypeWriter sub;
1002
1003   data_block_save (block, &saved);
1004   
1005   if (!_dbus_type_writer_recurse (writer,
1006                                   DBUS_TYPE_STRUCT,
1007                                   &sub))
1008     return FALSE;
1009
1010   if (!write_struct_with_int32s (block, &sub))
1011     {
1012       data_block_restore (block, &saved);
1013       return FALSE;
1014     }
1015   if (!write_struct_with_int32s (block, &sub))
1016     {
1017       data_block_restore (block, &saved);
1018       return FALSE;
1019     }
1020   if (!write_struct_with_int32s (block, &sub))
1021     {
1022       data_block_restore (block, &saved);
1023       return FALSE;
1024     }
1025
1026   if (!_dbus_type_writer_unrecurse (writer, &sub))
1027     {
1028       data_block_restore (block, &saved);
1029       return FALSE;
1030     }
1031   
1032   return TRUE;
1033 }
1034
1035 static dbus_bool_t
1036 read_struct_of_structs (DataBlock      *block,
1037                         DBusTypeReader *reader)
1038 {
1039   DBusTypeReader sub;
1040   
1041   check_expected_type (reader, DBUS_TYPE_STRUCT);
1042   
1043   _dbus_type_reader_recurse (reader, &sub);
1044
1045   if (!read_struct_with_int32s (block, &sub))
1046     return FALSE;
1047   _dbus_type_reader_next (&sub);
1048   if (!read_struct_with_int32s (block, &sub))
1049     return FALSE;
1050   _dbus_type_reader_next (&sub);
1051   if (!read_struct_with_int32s (block, &sub))
1052     return FALSE;
1053   
1054   return TRUE;
1055 }
1056
1057 static dbus_bool_t
1058 write_struct_of_structs_of_structs (DataBlock      *block,
1059                                     DBusTypeWriter *writer)
1060 {
1061   DataBlockState saved;
1062   DBusTypeWriter sub;
1063
1064   data_block_save (block, &saved);
1065   
1066   if (!_dbus_type_writer_recurse (writer,
1067                                   DBUS_TYPE_STRUCT,
1068                                   &sub))
1069     return FALSE;
1070
1071   if (!write_struct_of_structs (block, &sub))
1072     {
1073       data_block_restore (block, &saved);
1074       return FALSE;
1075     }
1076   if (!write_struct_of_structs (block, &sub))
1077     {
1078       data_block_restore (block, &saved);
1079       return FALSE;
1080     }
1081
1082   if (!_dbus_type_writer_unrecurse (writer, &sub))
1083     {
1084       data_block_restore (block, &saved);
1085       return FALSE;
1086     }
1087   
1088   return TRUE;
1089 }
1090
1091 static dbus_bool_t
1092 read_struct_of_structs_of_structs (DataBlock      *block,
1093                                    DBusTypeReader *reader)
1094 {
1095   DBusTypeReader sub;
1096   
1097   check_expected_type (reader, DBUS_TYPE_STRUCT);
1098   
1099   _dbus_type_reader_recurse (reader, &sub);
1100
1101   if (!read_struct_of_structs (block, &sub))
1102     return FALSE;
1103   _dbus_type_reader_next (&sub);
1104   if (!read_struct_of_structs (block, &sub))
1105     return FALSE;
1106   
1107   return TRUE;
1108 }
1109
1110 static dbus_bool_t
1111 write_array_of_int32 (DataBlock      *block,
1112                       DBusTypeWriter *writer)
1113 {
1114   dbus_int32_t v;
1115   DataBlockState saved;
1116   DBusTypeWriter sub;
1117
1118   data_block_save (block, &saved);
1119   
1120   if (!_dbus_type_writer_recurse_array (writer,
1121                                         DBUS_TYPE_INT32_AS_STRING,
1122                                         &sub))
1123     return FALSE;
1124
1125   v = SAMPLE_INT32_ALTERNATE;
1126   if (!_dbus_type_writer_write_basic (&sub,
1127                                       DBUS_TYPE_INT32,
1128                                       &v))
1129     {
1130       data_block_restore (block, &saved);
1131       return FALSE;
1132     }
1133
1134   v = SAMPLE_INT32;
1135   if (!_dbus_type_writer_write_basic (&sub,
1136                                       DBUS_TYPE_INT32,
1137                                       &v))
1138     {
1139       data_block_restore (block, &saved);
1140       return FALSE;
1141     }
1142
1143   v = SAMPLE_INT32;
1144   if (!_dbus_type_writer_write_basic (&sub,
1145                                       DBUS_TYPE_INT32,
1146                                       &v))
1147     {
1148       data_block_restore (block, &saved);
1149       return FALSE;
1150     }
1151   
1152   if (!_dbus_type_writer_unrecurse (writer, &sub))
1153     {
1154       data_block_restore (block, &saved);
1155       return FALSE;
1156     }
1157   
1158   return TRUE;
1159 }
1160
1161 static dbus_bool_t
1162 read_array_of_int32 (DataBlock      *block,
1163                      DBusTypeReader *reader)
1164 {
1165   dbus_int32_t v;
1166   DBusTypeReader sub;
1167
1168   check_expected_type (reader, DBUS_TYPE_ARRAY);
1169   
1170   _dbus_type_reader_recurse (reader, &sub);
1171
1172   check_expected_type (&sub, DBUS_TYPE_INT32);
1173   
1174   _dbus_type_reader_read_basic (&sub,
1175                                 (dbus_int32_t*) &v);
1176
1177   _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1178
1179   _dbus_type_reader_next (&sub);
1180   check_expected_type (&sub, DBUS_TYPE_INT32);
1181   
1182   _dbus_type_reader_read_basic (&sub,
1183                                 (dbus_int32_t*) &v);
1184
1185   _dbus_assert (v == SAMPLE_INT32);
1186
1187   _dbus_type_reader_next (&sub);
1188   check_expected_type (&sub, DBUS_TYPE_INT32);
1189   
1190   _dbus_type_reader_read_basic (&sub,
1191                                 (dbus_int32_t*) &v);
1192
1193   _dbus_assert (v == SAMPLE_INT32);
1194   
1195   return TRUE;
1196 }
1197
1198
1199 static dbus_bool_t
1200 write_array_of_int32_empty (DataBlock      *block,
1201                             DBusTypeWriter *writer)
1202 {
1203   DataBlockState saved;
1204   DBusTypeWriter sub;
1205
1206   data_block_save (block, &saved);
1207   
1208   if (!_dbus_type_writer_recurse_array (writer,
1209                                         DBUS_TYPE_INT32_AS_STRING,
1210                                         &sub))
1211     return FALSE;
1212   
1213   if (!_dbus_type_writer_unrecurse (writer, &sub))
1214     {
1215       data_block_restore (block, &saved);
1216       return FALSE;
1217     }
1218   
1219   return TRUE;
1220 }
1221
1222 static dbus_bool_t
1223 read_array_of_int32_empty (DataBlock      *block,
1224                            DBusTypeReader *reader)
1225 {
1226   DBusTypeReader sub;
1227
1228   check_expected_type (reader, DBUS_TYPE_ARRAY);
1229   
1230   _dbus_type_reader_recurse (reader, &sub);
1231
1232   check_expected_type (&sub, DBUS_TYPE_INVALID);
1233   
1234   return TRUE;
1235 }
1236
1237 static dbus_bool_t
1238 write_array_of_array_of_int32 (DataBlock      *block,
1239                                DBusTypeWriter *writer)
1240 {
1241   DataBlockState saved;
1242   DBusTypeWriter sub;
1243
1244   data_block_save (block, &saved);
1245   
1246   if (!_dbus_type_writer_recurse_array (writer,
1247                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1248                                         &sub))
1249     return FALSE;
1250
1251   if (!write_array_of_int32 (block, &sub))
1252     {
1253       data_block_restore (block, &saved);
1254       return FALSE;
1255     }
1256
1257   if (!write_array_of_int32 (block, &sub))
1258     {
1259       data_block_restore (block, &saved);
1260       return FALSE;
1261     }
1262
1263   if (!write_array_of_int32_empty (block, &sub))
1264     {
1265       data_block_restore (block, &saved);
1266       return FALSE;
1267     }
1268   
1269   if (!write_array_of_int32 (block, &sub))
1270     {
1271       data_block_restore (block, &saved);
1272       return FALSE;
1273     }
1274   
1275   if (!_dbus_type_writer_unrecurse (writer, &sub))
1276     {
1277       data_block_restore (block, &saved);
1278       return FALSE;
1279     }
1280   
1281   return TRUE;
1282 }
1283
1284 static dbus_bool_t
1285 read_array_of_array_of_int32 (DataBlock      *block,
1286                               DBusTypeReader *reader)
1287 {
1288   DBusTypeReader sub;
1289   
1290   check_expected_type (reader, DBUS_TYPE_ARRAY);
1291   
1292   _dbus_type_reader_recurse (reader, &sub);
1293
1294   if (!read_array_of_int32 (block, &sub))
1295     return FALSE;
1296   _dbus_type_reader_next (&sub);
1297   if (!read_array_of_int32 (block, &sub))
1298     return FALSE;
1299   _dbus_type_reader_next (&sub);
1300   if (!read_array_of_int32_empty (block, &sub))
1301     return FALSE;
1302   _dbus_type_reader_next (&sub);
1303   if (!read_array_of_int32 (block, &sub))
1304     return FALSE;
1305   _dbus_type_reader_next (&sub);
1306   
1307   return TRUE;
1308 }
1309
1310
1311 static dbus_bool_t
1312 write_array_of_array_of_int32_empty (DataBlock      *block,
1313                                      DBusTypeWriter *writer)
1314 {
1315   DataBlockState saved;
1316   DBusTypeWriter sub;
1317
1318   data_block_save (block, &saved);
1319   
1320   if (!_dbus_type_writer_recurse_array (writer,
1321                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1322                                         &sub))
1323     return FALSE;
1324
1325   if (!_dbus_type_writer_unrecurse (writer, &sub))
1326     {
1327       data_block_restore (block, &saved);
1328       return FALSE;
1329     }
1330   
1331   return TRUE;
1332 }
1333
1334 static dbus_bool_t
1335 read_array_of_array_of_int32_empty (DataBlock      *block,
1336                                     DBusTypeReader *reader)
1337 {
1338   DBusTypeReader sub;
1339   DBusTypeReader sub2;
1340   
1341   check_expected_type (reader, DBUS_TYPE_ARRAY);
1342   
1343   _dbus_type_reader_recurse (reader, &sub);
1344
1345   check_expected_type (reader, DBUS_TYPE_ARRAY);
1346
1347   _dbus_type_reader_recurse (&sub, &sub2);
1348
1349   check_expected_type (reader, DBUS_TYPE_INVALID);
1350   
1351   return TRUE;
1352 }
1353
1354 static dbus_bool_t
1355 write_array_of_array_of_array_of_int32 (DataBlock      *block,
1356                                         DBusTypeWriter *writer)
1357 {
1358   DataBlockState saved;
1359   DBusTypeWriter sub;
1360
1361   data_block_save (block, &saved);
1362   
1363   if (!_dbus_type_writer_recurse_array (writer,
1364                                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1365                                         &sub))
1366     return FALSE;
1367
1368   if (!write_array_of_array_of_int32 (block, &sub))
1369     {
1370       data_block_restore (block, &saved);
1371       return FALSE;
1372     }
1373
1374   if (!write_array_of_array_of_int32 (block, &sub))
1375     {
1376       data_block_restore (block, &saved);
1377       return FALSE;
1378     }
1379
1380   if (!write_array_of_array_of_int32_empty (block, &sub))
1381     {
1382       data_block_restore (block, &saved);
1383       return FALSE;
1384     }
1385   
1386   if (!_dbus_type_writer_unrecurse (writer, &sub))
1387     {
1388       data_block_restore (block, &saved);
1389       return FALSE;
1390     }
1391   
1392   return TRUE;
1393 }
1394
1395 static dbus_bool_t
1396 read_array_of_array_of_array_of_int32 (DataBlock      *block,
1397                                        DBusTypeReader *reader)
1398 {
1399   DBusTypeReader sub;
1400   
1401   check_expected_type (reader, DBUS_TYPE_ARRAY);
1402   
1403   _dbus_type_reader_recurse (reader, &sub);
1404
1405   if (!read_array_of_array_of_int32 (block, &sub))
1406     return FALSE;
1407   _dbus_type_reader_next (&sub);
1408   if (!read_array_of_array_of_int32 (block, &sub))
1409     return FALSE;
1410   _dbus_type_reader_next (&sub);
1411   if (!read_array_of_array_of_int32_empty (block, &sub))
1412     return FALSE;
1413   _dbus_type_reader_next (&sub);
1414   
1415   return TRUE;
1416 }
1417
1418 typedef enum {
1419   ITEM_INVALID = -1,
1420   ITEM_INT32 = 0,
1421   ITEM_STRUCT_WITH_INT32S,
1422   ITEM_STRUCT_OF_STRUCTS,
1423   ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
1424   ITEM_ARRAY_OF_INT32,
1425   ITEM_ARRAY_OF_INT32_EMPTY,
1426   ITEM_ARRAY_OF_ARRAY_OF_INT32,
1427   ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
1428   ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
1429   ITEM_LAST
1430 } WhichItem;
1431
1432
1433 typedef dbus_bool_t (* WriteItemFunc) (DataBlock      *block,
1434                                        DBusTypeWriter *writer);
1435 typedef dbus_bool_t (* ReadItemFunc)  (DataBlock      *block,
1436                                        DBusTypeReader *reader);
1437
1438 typedef struct
1439 {
1440   const char *desc;
1441   WhichItem which;
1442   WriteItemFunc write_item_func;
1443   ReadItemFunc read_item_func;
1444 } CheckMarshalItem;
1445
1446 static CheckMarshalItem items[] = {
1447   { "int32",
1448     ITEM_INT32, write_int32, read_int32 },
1449   { "struct with two int32",
1450     ITEM_STRUCT_WITH_INT32S, write_struct_with_int32s, read_struct_with_int32s },
1451   { "struct with three structs of two int32",
1452     ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
1453   { "struct of two structs of three structs of two int32",
1454     ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
1455     write_struct_of_structs_of_structs,
1456     read_struct_of_structs_of_structs },
1457   { "array of int32",
1458     ITEM_ARRAY_OF_INT32, write_array_of_int32, read_array_of_int32 },
1459   { "empty array of int32",
1460     ITEM_ARRAY_OF_INT32_EMPTY, write_array_of_int32_empty, read_array_of_int32_empty },
1461   { "array of array of int32",
1462     ITEM_ARRAY_OF_ARRAY_OF_INT32,
1463     write_array_of_array_of_int32, read_array_of_array_of_int32 },
1464   { "empty array of array of int32",
1465     ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
1466     write_array_of_array_of_int32_empty, read_array_of_array_of_int32_empty },
1467   { "array of array of array of int32",
1468     ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
1469     write_array_of_array_of_array_of_int32, read_array_of_array_of_array_of_int32 }
1470 };
1471
1472 typedef struct
1473 {
1474   /* Array of items from the above items[]; -1 terminated */
1475   int items[20];
1476 } TestRun;
1477
1478 static TestRun runs[] = {
1479   { { ITEM_INVALID } },
1480
1481   /* INT32 */
1482   { { ITEM_INT32, ITEM_INVALID } },
1483   { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
1484   { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
1485
1486   /* STRUCT_WITH_INT32S */
1487   { { ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1488   { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1489   { { ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1490   { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1491   { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1492
1493   /* STRUCT_OF_STRUCTS */
1494   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1495   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1496   { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1497   { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1498   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1499   { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1500
1501   /* STRUCT_OF_STRUCTS_OF_STRUCTS */
1502   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1503   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1504   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1505   { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1506   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1507   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1508
1509   /* ARRAY_OF_INT32 */
1510   { { ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1511   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1512   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1513   { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1514   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1515   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1516   { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1517   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1518   { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1519   { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1520
1521   /* ARRAY_OF_ARRAY_OF_INT32 */
1522   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1523   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1524   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1525   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1526   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1527   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1528   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1529   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1530   { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1531   { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1532
1533   /* ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32 */
1534   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1535   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1536   { { 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 } },
1537   { { 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 } },
1538   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1539   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1540   { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1541   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1542   { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1543   { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } }
1544
1545   
1546 };
1547
1548 static dbus_bool_t
1549 perform_one_run (DataBlock *block,
1550                  int        byte_order,
1551                  TestRun   *run)
1552 {
1553   DBusTypeReader reader;
1554   DBusTypeWriter writer;
1555   int i;
1556   DataBlockState saved;
1557   dbus_bool_t retval;
1558
1559   retval = FALSE;
1560
1561   {
1562     _dbus_verbose ("run byteorder %s items ",
1563                    byte_order == DBUS_LITTLE_ENDIAN ? "little" : "big");
1564     i = 0;
1565     while (run->items[i] != ITEM_INVALID)
1566       {
1567         CheckMarshalItem *item = &items[run->items[i]];
1568         
1569         _dbus_verbose ("%s ", item->desc);
1570         ++i;
1571       }
1572     _dbus_verbose (" = %d items\n", i);
1573   }
1574   
1575   data_block_save (block, &saved);
1576   
1577   data_block_init_reader_writer (block, 
1578                                  byte_order,
1579                                  &reader, &writer);
1580
1581   i = 0;
1582   while (run->items[i] != ITEM_INVALID)
1583     {
1584       CheckMarshalItem *item = &items[run->items[i]];
1585
1586       _dbus_verbose (">>writing %s\n", item->desc);
1587       
1588       if (!(* item->write_item_func) (block, &writer))
1589         goto out;
1590       ++i;
1591     }
1592
1593   i = 0;
1594   while (run->items[i] != ITEM_INVALID)
1595     {
1596       CheckMarshalItem *item = &items[run->items[i]];
1597
1598       _dbus_verbose (">>reading %s\n", item->desc);
1599       
1600       if (!(* item->read_item_func) (block, &reader))
1601         goto out;
1602
1603       _dbus_type_reader_next (&reader);
1604       
1605       ++i;
1606     }
1607   
1608   retval = TRUE;
1609   
1610  out:
1611   data_block_restore (block, &saved);
1612   return retval;
1613 }
1614
1615 static dbus_bool_t
1616 perform_all_runs (int byte_order,
1617                   int initial_offset)
1618 {
1619   int i;
1620   DataBlock block;
1621   dbus_bool_t retval;
1622
1623   retval = FALSE;
1624   
1625   if (!data_block_init (&block))
1626     return FALSE;
1627
1628   if (!_dbus_string_lengthen (&block.signature, initial_offset))
1629     goto out;
1630   
1631   if (!_dbus_string_lengthen (&block.body, initial_offset))
1632     goto out;
1633   
1634   i = 0;
1635   while (i < _DBUS_N_ELEMENTS (runs))
1636     {
1637       if (!perform_one_run (&block, byte_order, &runs[i]))
1638         goto out;
1639       
1640       ++i;
1641     }
1642
1643   retval = TRUE;
1644   
1645  out:
1646   data_block_free (&block);
1647   
1648   return retval;
1649 }
1650
1651 static dbus_bool_t
1652 perform_all_items (int byte_order,
1653                    int initial_offset)
1654 {
1655   int i;
1656   DataBlock block;
1657   dbus_bool_t retval;
1658   TestRun run;
1659
1660   retval = FALSE;
1661   
1662   if (!data_block_init (&block))
1663     return FALSE;
1664
1665
1666   if (!_dbus_string_lengthen (&block.signature, initial_offset))
1667     goto out;
1668   
1669   if (!_dbus_string_lengthen (&block.body, initial_offset))
1670     goto out;
1671
1672   /* Create a run containing all the items */
1673   i = 0;
1674   while (i < _DBUS_N_ELEMENTS (items))
1675     {
1676       _dbus_assert (i == items[i].which);
1677       
1678       run.items[i] = items[i].which;
1679       
1680       ++i;
1681     }
1682   
1683   run.items[i] = ITEM_INVALID;
1684
1685   if (!perform_one_run (&block, byte_order, &run))
1686     goto out;  
1687   
1688   retval = TRUE;
1689   
1690  out:
1691   data_block_free (&block);
1692   
1693   return retval;
1694 }
1695
1696 static dbus_bool_t
1697 recursive_marshal_test_iteration (void *data)
1698 {
1699   int i;
1700
1701   i = 0;
1702   while (i < 18)
1703     {
1704       if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
1705         return FALSE;
1706       if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
1707         return FALSE;
1708       if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
1709         return FALSE;
1710       if (!perform_all_items (DBUS_BIG_ENDIAN, i))
1711         return FALSE;
1712       
1713       ++i;
1714     }
1715
1716   return TRUE;
1717 }
1718
1719 dbus_bool_t _dbus_marshal_recursive_test (void);
1720
1721 dbus_bool_t
1722 _dbus_marshal_recursive_test (void)
1723 {
1724   _dbus_test_oom_handling ("recursive marshaling",
1725                            recursive_marshal_test_iteration,
1726                            NULL);  
1727   
1728   return TRUE;
1729 }
1730
1731 #if 1
1732 int
1733 main (int argc, char **argv)
1734 {
1735   _dbus_marshal_recursive_test ();
1736
1737   return 0;
1738 }
1739 #endif /* main() */
1740
1741 #endif /* DBUS_BUILD_TESTS */