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