Merge branch 'master' of drop.maemo.org:/git/monky
[monky] / src / dbus / dbus-marshal-recursive.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-marshal-recursive.c  Marshalling routines for recursive types
3  *
4  * Copyright (C) 2004, 2005 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-marshal-basic.h"
26 #include "dbus-signature.h"
27 #include "dbus-internals.h"
28
29 /**
30  * @addtogroup DBusMarshal
31  * @{
32  */
33
34 /** turn this on to get deluged in TypeReader verbose spam */
35 #define RECURSIVE_MARSHAL_READ_TRACE  0
36
37 /** turn this on to get deluged in TypeWriter verbose spam */
38 #define RECURSIVE_MARSHAL_WRITE_TRACE 0
39
40 static void
41 free_fixups (DBusList **fixups)
42 {
43   DBusList *link;
44
45   link = _dbus_list_get_first_link (fixups);
46   while (link != NULL)
47     {
48       DBusList *next;
49
50       next = _dbus_list_get_next_link (fixups, link);
51
52       dbus_free (link->data);
53       _dbus_list_free_link (link);
54
55       link = next;
56     }
57
58   *fixups = NULL;
59 }
60
61 static void
62 apply_and_free_fixups (DBusList      **fixups,
63                        DBusTypeReader *reader)
64 {
65   DBusList *link;
66
67 #if RECURSIVE_MARSHAL_WRITE_TRACE
68   if (*fixups)
69     _dbus_verbose (" %d FIXUPS to apply\n",
70                    _dbus_list_get_length (fixups));
71 #endif
72
73   link = _dbus_list_get_first_link (fixups);
74   while (link != NULL)
75     {
76       DBusList *next;
77
78       next = _dbus_list_get_next_link (fixups, link);
79
80       if (reader)
81         {
82           DBusArrayLenFixup *f;
83
84           f = link->data;
85
86 #if RECURSIVE_MARSHAL_WRITE_TRACE
87           _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",
88                          reader, f->len_pos_in_reader, f->new_len,
89                          _dbus_marshal_read_uint32 (reader->value_str,
90                                                     f->len_pos_in_reader,
91                                                     reader->byte_order, NULL));
92 #endif
93
94           _dbus_marshal_set_uint32 ((DBusString*) reader->value_str,
95                                     f->len_pos_in_reader,
96                                     f->new_len,
97                                     reader->byte_order);
98         }
99
100       dbus_free (link->data);
101       _dbus_list_free_link (link);
102
103       link = next;
104     }
105
106   *fixups = NULL;
107 }
108
109 /**
110  * Virtual table for a type reader.
111  */
112 struct DBusTypeReaderClass
113 {
114   const char *name;       /**< name for debugging */
115   int         id;         /**< index in all_reader_classes */
116   dbus_bool_t types_only; /**< only iterates over types, not values */
117   void        (* recurse)          (DBusTypeReader        *sub,
118                                     DBusTypeReader        *parent); /**< recurse with this reader as sub */
119   dbus_bool_t (* check_finished)   (const DBusTypeReader  *reader); /**< check whether reader is at the end */
120   void        (* next)             (DBusTypeReader        *reader,
121                                     int                    current_type); /**< go to the next value */
122 };
123
124 static int
125 element_type_get_alignment (const DBusString *str,
126                             int               pos)
127 {
128   return _dbus_type_get_alignment (_dbus_first_type_in_signature (str, pos));
129 }
130
131 static void
132 reader_init (DBusTypeReader    *reader,
133              int                byte_order,
134              const DBusString  *type_str,
135              int                type_pos,
136              const DBusString  *value_str,
137              int                value_pos)
138 {
139   reader->byte_order = byte_order;
140   reader->finished = FALSE;
141   reader->type_str = type_str;
142   reader->type_pos = type_pos;
143   reader->value_str = value_str;
144   reader->value_pos = value_pos;
145 }
146
147 static void
148 base_reader_recurse (DBusTypeReader *sub,
149                      DBusTypeReader *parent)
150 {
151   /* point subreader at the same place as parent */
152   reader_init (sub,
153                parent->byte_order,
154                parent->type_str,
155                parent->type_pos,
156                parent->value_str,
157                parent->value_pos);
158 }
159
160 static void
161 struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub,
162                                                 DBusTypeReader *parent)
163 {
164   base_reader_recurse (sub, parent);
165   
166   _dbus_assert (_dbus_string_get_byte (sub->type_str,
167                                        sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR ||
168                 _dbus_string_get_byte (sub->type_str,
169                                        sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR);
170
171   sub->type_pos += 1;
172 }
173
174 static void
175 struct_or_dict_entry_reader_recurse (DBusTypeReader *sub,
176                                      DBusTypeReader *parent)
177 {
178   struct_or_dict_entry_types_only_reader_recurse (sub, parent);
179
180   /* struct and dict entry have 8 byte alignment */
181   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
182 }
183
184 static void
185 array_types_only_reader_recurse (DBusTypeReader *sub,
186                                  DBusTypeReader *parent)
187 {
188   base_reader_recurse (sub, parent);
189
190   /* point type_pos at the array element type */
191   sub->type_pos += 1;
192
193   /* Init with values likely to crash things if misused */
194   sub->u.array.start_pos = _DBUS_INT_MAX;
195   sub->array_len_offset = 7;
196 }
197
198 /** compute position of array length given array_len_offset, which is
199     the offset back from start_pos to end of the len */
200 #define ARRAY_READER_LEN_POS(reader) \
201   ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4)
202
203 static int
204 array_reader_get_array_len (const DBusTypeReader *reader)
205 {
206   dbus_uint32_t array_len;
207   int len_pos;
208
209   len_pos = ARRAY_READER_LEN_POS (reader);
210
211   _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos);
212   array_len = _dbus_unpack_uint32 (reader->byte_order,
213                                    _dbus_string_get_const_data_len (reader->value_str, len_pos, 4));
214
215 #if RECURSIVE_MARSHAL_READ_TRACE
216   _dbus_verbose ("   reader %p len_pos %d array len %u len_offset %d\n",
217                  reader, len_pos, array_len, reader->array_len_offset);
218 #endif
219
220   _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
221
222   return array_len;
223 }
224
225 static void
226 array_reader_recurse (DBusTypeReader *sub,
227                       DBusTypeReader *parent)
228 {
229   int alignment;
230   int len_pos;
231
232   array_types_only_reader_recurse (sub, parent);
233
234   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
235
236   len_pos = sub->value_pos;
237
238   sub->value_pos += 4; /* for the length */
239
240   alignment = element_type_get_alignment (sub->type_str,
241                                           sub->type_pos);
242
243   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
244
245   sub->u.array.start_pos = sub->value_pos;
246   _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
247   sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
248
249 #if RECURSIVE_MARSHAL_READ_TRACE
250   _dbus_verbose ("    type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
251                  sub,
252                  sub->u.array.start_pos,
253                  sub->array_len_offset,
254                  array_reader_get_array_len (sub),
255                  _dbus_type_to_string (_dbus_first_type_in_signature (sub->type_str,
256                                                                 sub->type_pos)));
257 #endif
258 }
259
260 static void
261 variant_reader_recurse (DBusTypeReader *sub,
262                         DBusTypeReader *parent)
263 {
264   int sig_len;
265   int contained_alignment;
266
267   base_reader_recurse (sub, parent);
268
269   /* Variant is 1 byte sig length (without nul), signature with nul,
270    * padding to 8-boundary, then values
271    */
272
273   sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
274
275   sub->type_str = sub->value_str;
276   sub->type_pos = sub->value_pos + 1;
277
278   sub->value_pos = sub->type_pos + sig_len + 1;
279
280   contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (sub->type_str,
281                                                                            sub->type_pos));
282   
283   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
284
285 #if RECURSIVE_MARSHAL_READ_TRACE
286   _dbus_verbose ("    type reader %p variant containing '%s'\n",
287                  sub,
288                  _dbus_string_get_const_data_len (sub->type_str,
289                                                   sub->type_pos, 0));
290 #endif
291 }
292
293 static dbus_bool_t
294 array_reader_check_finished (const DBusTypeReader *reader)
295 {
296   int end_pos;
297
298   /* return the array element type if elements remain, and
299    * TYPE_INVALID otherwise
300    */
301
302   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
303
304   _dbus_assert (reader->value_pos <= end_pos);
305   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
306
307   return reader->value_pos == end_pos;
308 }
309
310 static void
311 skip_one_complete_type (const DBusString *type_str,
312                         int              *type_pos)
313 {
314   _dbus_type_signature_next (_dbus_string_get_const_data (type_str),
315                              type_pos);
316 }
317
318 /**
319  * Skips to the next "complete" type inside a type signature.
320  * The signature is read starting at type_pos, and the next
321  * type position is stored in the same variable.
322  *
323  * @param type_str a type signature (must be valid)
324  * @param type_pos an integer position in the type signature (in and out)
325  */
326 void
327 _dbus_type_signature_next (const char       *type_str,
328                            int              *type_pos)
329 {
330   const unsigned char *p;
331   const unsigned char *start;
332
333   _dbus_assert (type_str != NULL);
334   _dbus_assert (type_pos != NULL);
335   
336   start = type_str;
337   p = start + *type_pos;
338
339   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
340   _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
341   
342   while (*p == DBUS_TYPE_ARRAY)
343     ++p;
344
345   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
346   _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
347   
348   if (*p == DBUS_STRUCT_BEGIN_CHAR)
349     {
350       int depth;
351
352       depth = 1;
353
354       while (TRUE)
355         {
356           _dbus_assert (*p != DBUS_TYPE_INVALID);
357
358           ++p;
359
360           _dbus_assert (*p != DBUS_TYPE_INVALID);
361
362           if (*p == DBUS_STRUCT_BEGIN_CHAR)
363             depth += 1;
364           else if (*p == DBUS_STRUCT_END_CHAR)
365             {
366               depth -= 1;
367               if (depth == 0)
368                 {
369                   ++p;
370                   break;
371                 }
372             }
373         }
374     }
375   else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
376     {
377       int depth;
378
379       depth = 1;
380
381       while (TRUE)
382         {
383           _dbus_assert (*p != DBUS_TYPE_INVALID);
384
385           ++p;
386
387           _dbus_assert (*p != DBUS_TYPE_INVALID);
388
389           if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
390             depth += 1;
391           else if (*p == DBUS_DICT_ENTRY_END_CHAR)
392             {
393               depth -= 1;
394               if (depth == 0)
395                 {
396                   ++p;
397                   break;
398                 }
399             }
400         }
401     }
402   else
403     {
404       ++p;
405     }
406
407   *type_pos = (int) (p - start);
408 }
409
410 static int
411 find_len_of_complete_type (const DBusString *type_str,
412                            int               type_pos)
413 {
414   int end;
415
416   end = type_pos;
417
418   skip_one_complete_type (type_str, &end);
419
420   return end - type_pos;
421 }
422
423 static void
424 base_reader_next (DBusTypeReader *reader,
425                   int             current_type)
426 {
427   switch (current_type)
428     {
429     case DBUS_TYPE_DICT_ENTRY:
430     case DBUS_TYPE_STRUCT:
431     case DBUS_TYPE_VARIANT:
432       /* Scan forward over the entire container contents */
433       {
434         DBusTypeReader sub;
435
436         if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT)
437           ;
438         else
439           {
440             /* Recurse into the struct or variant */
441             _dbus_type_reader_recurse (reader, &sub);
442
443             /* Skip everything in this subreader */
444             while (_dbus_type_reader_next (&sub))
445               {
446                 /* nothing */;
447               }
448           }
449         if (!reader->klass->types_only)
450           reader->value_pos = sub.value_pos;
451
452         /* Now we are at the end of this container; for variants, the
453          * subreader's type_pos is totally inapplicable (it's in the
454          * value string) but we know that we increment by one past the
455          * DBUS_TYPE_VARIANT
456          */
457         if (current_type == DBUS_TYPE_VARIANT)
458           reader->type_pos += 1;
459         else
460           reader->type_pos = sub.type_pos;
461       }
462       break;
463
464     case DBUS_TYPE_ARRAY:
465       {
466         if (!reader->klass->types_only)
467           _dbus_marshal_skip_array (reader->value_str,
468                                     _dbus_first_type_in_signature (reader->type_str,
469                                                                    reader->type_pos + 1),
470                                     reader->byte_order,
471                                     &reader->value_pos);
472
473         skip_one_complete_type (reader->type_str, &reader->type_pos);
474       }
475       break;
476
477     default:
478       if (!reader->klass->types_only)
479         _dbus_marshal_skip_basic (reader->value_str,
480                                   current_type, reader->byte_order,
481                                   &reader->value_pos);
482
483       reader->type_pos += 1;
484       break;
485     }
486 }
487
488 static void
489 struct_reader_next (DBusTypeReader *reader,
490                     int             current_type)
491 {
492   int t;
493
494   base_reader_next (reader, current_type);
495
496   /* for STRUCT containers we return FALSE at the end of the struct,
497    * for INVALID we return FALSE at the end of the signature.
498    * In both cases we arrange for get_current_type() to return INVALID
499    * which is defined to happen iff we're at the end (no more next())
500    */
501   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
502   if (t == DBUS_STRUCT_END_CHAR)
503     {
504       reader->type_pos += 1;
505       reader->finished = TRUE;
506     }
507 }
508
509 static void
510 dict_entry_reader_next (DBusTypeReader *reader,
511                         int             current_type)
512 {
513   int t;
514
515   base_reader_next (reader, current_type);
516
517   /* for STRUCT containers we return FALSE at the end of the struct,
518    * for INVALID we return FALSE at the end of the signature.
519    * In both cases we arrange for get_current_type() to return INVALID
520    * which is defined to happen iff we're at the end (no more next())
521    */
522   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
523   if (t == DBUS_DICT_ENTRY_END_CHAR)
524     {
525       reader->type_pos += 1;
526       reader->finished = TRUE;
527     }
528 }
529
530 static void
531 array_types_only_reader_next (DBusTypeReader *reader,
532                               int             current_type)
533 {
534   /* We have one "element" to be iterated over
535    * in each array, which is its element type.
536    * So the finished flag indicates whether we've
537    * iterated over it yet or not.
538    */
539   reader->finished = TRUE;
540 }
541
542 static void
543 array_reader_next (DBusTypeReader *reader,
544                    int             current_type)
545 {
546   /* Skip one array element */
547   int end_pos;
548
549   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
550
551 #if RECURSIVE_MARSHAL_READ_TRACE
552   _dbus_verbose ("  reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
553                  reader,
554                  reader->u.array.start_pos,
555                  end_pos, reader->value_pos,
556                  _dbus_type_to_string (current_type));
557 #endif
558
559   _dbus_assert (reader->value_pos < end_pos);
560   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
561
562   switch (_dbus_first_type_in_signature (reader->type_str,
563                                          reader->type_pos))
564     {
565     case DBUS_TYPE_DICT_ENTRY:
566     case DBUS_TYPE_STRUCT:
567     case DBUS_TYPE_VARIANT:
568       {
569         DBusTypeReader sub;
570
571         /* Recurse into the struct or variant */
572         _dbus_type_reader_recurse (reader, &sub);
573
574         /* Skip everything in this element */
575         while (_dbus_type_reader_next (&sub))
576           {
577             /* nothing */;
578           }
579
580         /* Now we are at the end of this element */
581         reader->value_pos = sub.value_pos;
582       }
583       break;
584
585     case DBUS_TYPE_ARRAY:
586       {
587         _dbus_marshal_skip_array (reader->value_str,
588                                   _dbus_first_type_in_signature (reader->type_str,
589                                                            reader->type_pos + 1),
590                                   reader->byte_order,
591                                   &reader->value_pos);
592       }
593       break;
594
595     default:
596       {
597         _dbus_marshal_skip_basic (reader->value_str,
598                                   current_type, reader->byte_order,
599                                   &reader->value_pos);
600       }
601       break;
602     }
603
604 #if RECURSIVE_MARSHAL_READ_TRACE
605   _dbus_verbose ("  reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
606                  reader,
607                  reader->u.array.start_pos,
608                  end_pos, reader->value_pos,
609                  _dbus_type_to_string (current_type));
610 #endif
611
612   _dbus_assert (reader->value_pos <= end_pos);
613
614   if (reader->value_pos == end_pos)
615     {
616       skip_one_complete_type (reader->type_str,
617                               &reader->type_pos);
618     }
619 }
620
621 static const DBusTypeReaderClass body_reader_class = {
622   "body", 0,
623   FALSE,
624   NULL, /* body is always toplevel, so doesn't get recursed into */
625   NULL,
626   base_reader_next
627 };
628
629 static const DBusTypeReaderClass body_types_only_reader_class = {
630   "body types", 1,
631   TRUE,
632   NULL, /* body is always toplevel, so doesn't get recursed into */
633   NULL,
634   base_reader_next
635 };
636
637 static const DBusTypeReaderClass struct_reader_class = {
638   "struct", 2,
639   FALSE,
640   struct_or_dict_entry_reader_recurse,
641   NULL,
642   struct_reader_next
643 };
644
645 static const DBusTypeReaderClass struct_types_only_reader_class = {
646   "struct types", 3,
647   TRUE,
648   struct_or_dict_entry_types_only_reader_recurse,
649   NULL,
650   struct_reader_next
651 };
652
653 static const DBusTypeReaderClass dict_entry_reader_class = {
654   "dict_entry", 4,
655   FALSE,
656   struct_or_dict_entry_reader_recurse,
657   NULL,
658   dict_entry_reader_next
659 };
660
661 static const DBusTypeReaderClass dict_entry_types_only_reader_class = {
662   "dict_entry types", 5,
663   TRUE,
664   struct_or_dict_entry_types_only_reader_recurse,
665   NULL,
666   dict_entry_reader_next
667 };
668
669 static const DBusTypeReaderClass array_reader_class = {
670   "array", 6,
671   FALSE,
672   array_reader_recurse,
673   array_reader_check_finished,
674   array_reader_next
675 };
676
677 static const DBusTypeReaderClass array_types_only_reader_class = {
678   "array types", 7,
679   TRUE,
680   array_types_only_reader_recurse,
681   NULL,
682   array_types_only_reader_next
683 };
684
685 static const DBusTypeReaderClass variant_reader_class = {
686   "variant", 8,
687   FALSE,
688   variant_reader_recurse,
689   NULL,
690   base_reader_next
691 };
692
693 #ifndef DBUS_DISABLE_ASSERT
694 static const DBusTypeReaderClass * const
695 all_reader_classes[] = {
696   &body_reader_class,
697   &body_types_only_reader_class,
698   &struct_reader_class,
699   &struct_types_only_reader_class,
700   &dict_entry_reader_class,
701   &dict_entry_types_only_reader_class,
702   &array_reader_class,
703   &array_types_only_reader_class,
704   &variant_reader_class
705 };
706 #endif
707
708 /**
709  * Initializes a type reader.
710  *
711  * @param reader the reader
712  * @param byte_order the byte order of the block to read
713  * @param type_str the signature of the block to read
714  * @param type_pos location of signature
715  * @param value_str the string containing values block
716  * @param value_pos start of values block
717  */
718 void
719 _dbus_type_reader_init (DBusTypeReader    *reader,
720                         int                byte_order,
721                         const DBusString  *type_str,
722                         int                type_pos,
723                         const DBusString  *value_str,
724                         int                value_pos)
725 {
726   reader->klass = &body_reader_class;
727
728   reader_init (reader, byte_order, type_str, type_pos,
729                value_str, value_pos);
730
731 #if RECURSIVE_MARSHAL_READ_TRACE
732   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
733                  reader, reader->type_pos, reader->value_pos,
734                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
735 #endif
736 }
737
738 /**
739  * Like _dbus_type_reader_init() but the iteration is over the
740  * signature, not over values.
741  *
742  * @param reader the reader
743  * @param type_str the signature string
744  * @param type_pos location in the signature string
745  */
746 void
747 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
748                                    const DBusString  *type_str,
749                                    int                type_pos)
750 {
751   reader->klass = &body_types_only_reader_class;
752
753   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
754                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
755
756 #if RECURSIVE_MARSHAL_READ_TRACE
757   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
758                  reader, reader->type_pos,
759                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
760 #endif
761 }
762
763 /**
764  * Gets the type of the value the reader is currently pointing to;
765  * or for a types-only reader gets the type it's currently pointing to.
766  * If the reader is at the end of a block or end of a container such
767  * as an array, returns #DBUS_TYPE_INVALID.
768  *
769  * @param reader the reader
770  */
771 int
772 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
773 {
774   int t;
775
776   if (reader->finished ||
777       (reader->klass->check_finished &&
778        (* reader->klass->check_finished) (reader)))
779     t = DBUS_TYPE_INVALID;
780   else
781     t = _dbus_first_type_in_signature (reader->type_str,
782                                        reader->type_pos);
783
784   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
785   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
786   _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
787   _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR);
788   
789 #if 0
790   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
791                  reader, reader->type_pos,
792                  _dbus_type_to_string (t));
793 #endif
794
795   return t;
796 }
797
798 /**
799  * Gets the type of an element of the array the reader is currently
800  * pointing to. It's an error to call this if
801  * _dbus_type_reader_get_current_type() doesn't return #DBUS_TYPE_ARRAY
802  * for this reader.
803  *
804  * @param reader the reader
805  */
806 int
807 _dbus_type_reader_get_element_type (const DBusTypeReader  *reader)
808 {
809   int element_type;
810
811   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
812
813   element_type = _dbus_first_type_in_signature (reader->type_str,
814                                           reader->type_pos + 1);
815
816   return element_type;
817 }
818
819 /**
820  * Gets the current position in the value block
821  * @param reader the reader
822  */
823 int
824 _dbus_type_reader_get_value_pos (const DBusTypeReader  *reader)
825 {
826   return reader->value_pos;
827 }
828
829 /**
830  * Get the address of the marshaled value in the data being read.  The
831  * address may not be aligned; you have to align it to the type of the
832  * value you want to read. Most of the demarshal routines do this for
833  * you.
834  *
835  * @param reader the reader
836  * @param value_location the address of the marshaled value
837  */
838 void
839 _dbus_type_reader_read_raw (const DBusTypeReader  *reader,
840                             const unsigned char  **value_location)
841 {
842   _dbus_assert (!reader->klass->types_only);
843
844   *value_location = _dbus_string_get_const_data_len (reader->value_str,
845                                                      reader->value_pos,
846                                                      0);
847 }
848
849 /**
850  * Reads a basic-typed value, as with _dbus_marshal_read_basic().
851  *
852  * @param reader the reader
853  * @param value the address of the value
854  */
855 void
856 _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
857                               void                    *value)
858 {
859   int t;
860
861   _dbus_assert (!reader->klass->types_only);
862
863   t = _dbus_type_reader_get_current_type (reader);
864
865   _dbus_marshal_read_basic (reader->value_str,
866                             reader->value_pos,
867                             t, value,
868                             reader->byte_order,
869                             NULL);
870
871
872 #if RECURSIVE_MARSHAL_READ_TRACE
873   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
874                  reader, reader->type_pos, reader->value_pos,
875                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
876 #endif
877 }
878
879 /**
880  * Returns the number of bytes in the array.
881  *
882  * @param reader the reader to read from
883  * @returns the number of bytes in the array
884  */
885 int
886 _dbus_type_reader_get_array_length (const DBusTypeReader  *reader)
887 {
888   _dbus_assert (!reader->klass->types_only);
889   _dbus_assert (reader->klass == &array_reader_class);
890
891   return array_reader_get_array_len (reader);
892 }
893
894 /**
895  * Reads a block of fixed-length basic values, from the current point
896  * in an array to the end of the array.  Does not work for arrays of
897  * string or container types.
898  *
899  * This function returns the array in-place; it does not make a copy,
900  * and it does not swap the bytes.
901  *
902  * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back
903  * and the "value" argument should be a "const double**" and so on.
904  *
905  * @param reader the reader to read from
906  * @param value place to return the array values
907  * @param n_elements place to return number of array elements
908  */
909 void
910 _dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,
911                                     void                  *value,
912                                     int                   *n_elements)
913 {
914   int element_type;
915   int end_pos;
916   int remaining_len;
917   int alignment;
918   int total_len;
919
920   _dbus_assert (!reader->klass->types_only);
921   _dbus_assert (reader->klass == &array_reader_class);
922
923   element_type = _dbus_first_type_in_signature (reader->type_str,
924                                                 reader->type_pos);
925
926   _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
927   _dbus_assert (dbus_type_is_fixed (element_type));
928
929   alignment = _dbus_type_get_alignment (element_type);
930
931   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
932
933   total_len = array_reader_get_array_len (reader);
934   end_pos = reader->u.array.start_pos + total_len;
935   remaining_len = end_pos - reader->value_pos;
936
937 #if RECURSIVE_MARSHAL_READ_TRACE
938   _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",
939                  end_pos, total_len, remaining_len, reader->value_pos);
940 #endif
941
942   _dbus_assert (remaining_len <= total_len);
943
944   if (remaining_len == 0)
945     *(const DBusBasicValue**) value = NULL;
946   else
947     *(const DBusBasicValue**) value =
948       (void*) _dbus_string_get_const_data_len (reader->value_str,
949                                                reader->value_pos,
950                                                remaining_len);
951
952   *n_elements = remaining_len / alignment;
953   _dbus_assert ((remaining_len % alignment) == 0);
954
955 #if RECURSIVE_MARSHAL_READ_TRACE
956   _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
957                  reader, reader->type_pos, reader->value_pos,
958                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
959 #endif
960 }
961
962 /**
963  * Initialize a new reader pointing to the first type and
964  * corresponding value that's a child of the current container. It's
965  * an error to call this if the current type is a non-container.
966  *
967  * Note that DBusTypeReader traverses values, not types. So if you
968  * have an empty array of array of int, you can't recurse into it. You
969  * can only recurse into each element.
970  *
971  * @param reader the reader
972  * @param sub a reader to init pointing to the first child
973  */
974 void
975 _dbus_type_reader_recurse (DBusTypeReader *reader,
976                            DBusTypeReader *sub)
977 {
978   int t;
979
980   t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos);
981
982   switch (t)
983     {
984     case DBUS_TYPE_STRUCT:
985       if (reader->klass->types_only)
986         sub->klass = &struct_types_only_reader_class;
987       else
988         sub->klass = &struct_reader_class;
989       break;
990     case DBUS_TYPE_DICT_ENTRY:
991       if (reader->klass->types_only)
992         sub->klass = &dict_entry_types_only_reader_class;
993       else
994         sub->klass = &dict_entry_reader_class;
995       break;
996     case DBUS_TYPE_ARRAY:
997       if (reader->klass->types_only)
998         sub->klass = &array_types_only_reader_class;
999       else
1000         sub->klass = &array_reader_class;
1001       break;
1002     case DBUS_TYPE_VARIANT:
1003       if (reader->klass->types_only)
1004         _dbus_assert_not_reached ("can't recurse into variant typecode");
1005       else
1006         sub->klass = &variant_reader_class;
1007       break;
1008     default:
1009       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
1010 #ifndef DBUS_DISABLE_CHECKS
1011       if (t == DBUS_TYPE_INVALID)
1012         _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n");
1013 #endif /* DBUS_DISABLE_CHECKS */
1014
1015       _dbus_assert_not_reached ("don't yet handle recursing into this type");
1016     }
1017
1018   _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
1019
1020   (* sub->klass->recurse) (sub, reader);
1021
1022 #if RECURSIVE_MARSHAL_READ_TRACE
1023   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
1024                  sub, sub->type_pos, sub->value_pos,
1025                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
1026 #endif
1027 }
1028
1029 /**
1030  * Skip to the next value on this "level". e.g. the next field in a
1031  * struct, the next value in an array. Returns FALSE at the end of the
1032  * current container.
1033  *
1034  * @param reader the reader
1035  * @returns FALSE if nothing more to read at or below this level
1036  */
1037 dbus_bool_t
1038 _dbus_type_reader_next (DBusTypeReader *reader)
1039 {
1040   int t;
1041
1042   t = _dbus_type_reader_get_current_type (reader);
1043
1044 #if RECURSIVE_MARSHAL_READ_TRACE
1045   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1046                  reader, reader->type_pos, reader->value_pos,
1047                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1048                  _dbus_type_to_string (t));
1049 #endif
1050
1051   if (t == DBUS_TYPE_INVALID)
1052     return FALSE;
1053
1054   (* reader->klass->next) (reader, t);
1055
1056 #if RECURSIVE_MARSHAL_READ_TRACE
1057   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1058                  reader, reader->type_pos, reader->value_pos,
1059                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1060                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
1061 #endif
1062
1063   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
1064 }
1065
1066 /**
1067  * Check whether there's another value on this "level". e.g. the next
1068  * field in a struct, the next value in an array. Returns FALSE at the
1069  * end of the current container.
1070  *
1071  * You probably don't want to use this; it makes for an awkward for/while
1072  * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)"
1073  *
1074  * @param reader the reader
1075  * @returns FALSE if nothing more to read at or below this level
1076  */
1077 dbus_bool_t
1078 _dbus_type_reader_has_next (const DBusTypeReader *reader)
1079 {
1080   /* Not efficient but works for now. */
1081   DBusTypeReader copy;
1082
1083   copy = *reader;
1084   return _dbus_type_reader_next (&copy);
1085 }
1086
1087 /**
1088  * Gets the string and range of said string containing the signature
1089  * of the current value. Essentially a more complete version of
1090  * _dbus_type_reader_get_current_type() (returns the full type
1091  * rather than only the outside of the onion).
1092  *
1093  * Note though that the first byte in a struct signature is
1094  * #DBUS_STRUCT_BEGIN_CHAR while the current type will be
1095  * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the
1096  * signature is always the same as the current type. Another
1097  * difference is that this function will still return a signature when
1098  * inside an empty array; say you recurse into empty array of int32,
1099  * the signature is "i" but the current type will always be
1100  * #DBUS_TYPE_INVALID since there are no elements to be currently
1101  * pointing to.
1102  *
1103  * @param reader the reader
1104  * @param str_p place to return the string with the type in it
1105  * @param start_p place to return start of the type
1106  * @param len_p place to return the length of the type
1107  */
1108 void
1109 _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
1110                                  const DBusString     **str_p,
1111                                  int                   *start_p,
1112                                  int                   *len_p)
1113 {
1114   *str_p = reader->type_str;
1115   *start_p = reader->type_pos;
1116   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
1117 }
1118
1119 typedef struct
1120 {
1121   DBusString replacement; /**< Marshaled value including alignment padding */
1122   int padding;            /**< How much of the replacement block is padding */
1123 } ReplacementBlock;
1124
1125 static dbus_bool_t
1126 replacement_block_init (ReplacementBlock *block,
1127                         DBusTypeReader   *reader)
1128 {
1129   if (!_dbus_string_init (&block->replacement))
1130     return FALSE;
1131
1132   /* % 8 is the padding to have the same align properties in
1133    * our replacement string as we do at the position being replaced
1134    */
1135   block->padding = reader->value_pos % 8;
1136
1137   if (!_dbus_string_lengthen (&block->replacement, block->padding))
1138     goto oom;
1139
1140   return TRUE;
1141
1142  oom:
1143   _dbus_string_free (&block->replacement);
1144   return FALSE;
1145 }
1146
1147 static dbus_bool_t
1148 replacement_block_replace (ReplacementBlock     *block,
1149                            DBusTypeReader       *reader,
1150                            const DBusTypeReader *realign_root)
1151 {
1152   DBusTypeWriter writer;
1153   DBusTypeReader realign_reader;
1154   DBusList *fixups;
1155   int orig_len;
1156
1157   _dbus_assert (realign_root != NULL);
1158
1159   orig_len = _dbus_string_get_length (&block->replacement);
1160
1161   realign_reader = *realign_root;
1162
1163 #if RECURSIVE_MARSHAL_WRITE_TRACE
1164   _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
1165                  &writer, _dbus_string_get_length (&block->replacement));
1166 #endif
1167   _dbus_type_writer_init_values_only (&writer,
1168                                       realign_reader.byte_order,
1169                                       realign_reader.type_str,
1170                                       realign_reader.type_pos,
1171                                       &block->replacement,
1172                                       _dbus_string_get_length (&block->replacement));
1173
1174   _dbus_assert (realign_reader.value_pos <= reader->value_pos);
1175
1176 #if RECURSIVE_MARSHAL_WRITE_TRACE
1177   _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
1178                  realign_reader.value_pos, &writer, reader->value_pos);
1179 #endif
1180   fixups = NULL;
1181   if (!_dbus_type_writer_write_reader_partial (&writer,
1182                                                &realign_reader,
1183                                                reader,
1184                                                block->padding,
1185                                                _dbus_string_get_length (&block->replacement) - block->padding,
1186                                                &fixups))
1187     goto oom;
1188
1189 #if RECURSIVE_MARSHAL_WRITE_TRACE
1190   _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
1191                  _dbus_string_get_length (&block->replacement) - block->padding);
1192   _dbus_verbose_bytes_of_string (&block->replacement, block->padding,
1193                                  _dbus_string_get_length (&block->replacement) - block->padding);
1194   _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
1195                  reader->value_pos, reader->value_pos % 8,
1196                  realign_reader.value_pos - reader->value_pos,
1197                  realign_reader.value_pos);
1198   _dbus_verbose_bytes_of_string (reader->value_str,
1199                                  reader->value_pos,
1200                                  realign_reader.value_pos - reader->value_pos);
1201 #endif
1202
1203   /* Move the replacement into position
1204    * (realign_reader should now be at the end of the block to be replaced)
1205    */
1206   if (!_dbus_string_replace_len (&block->replacement, block->padding,
1207                                  _dbus_string_get_length (&block->replacement) - block->padding,
1208                                  (DBusString*) reader->value_str,
1209                                  reader->value_pos,
1210                                  realign_reader.value_pos - reader->value_pos))
1211     goto oom;
1212
1213   /* Process our fixups now that we can't have an OOM error */
1214   apply_and_free_fixups (&fixups, reader);
1215
1216   return TRUE;
1217
1218  oom:
1219   _dbus_string_set_length (&block->replacement, orig_len);
1220   free_fixups (&fixups);
1221   return FALSE;
1222 }
1223
1224 static void
1225 replacement_block_free (ReplacementBlock *block)
1226 {
1227   _dbus_string_free (&block->replacement);
1228 }
1229
1230 /* In the variable-length case, we have to fix alignment after we insert.
1231  * The strategy is as follows:
1232  *
1233  *  - pad a new string to have the same alignment as the
1234  *    start of the current basic value
1235  *  - write the new basic value
1236  *  - copy from the original reader to the new string,
1237  *    which will fix the alignment of types following
1238  *    the new value
1239  *    - this copy has to start at realign_root,
1240  *      but not really write anything until it
1241  *      passes the value being set
1242  *    - as an optimization, we can stop copying
1243  *      when the source and dest values are both
1244  *      on an 8-boundary, since we know all following
1245  *      padding and alignment will be identical
1246  *  - copy the new string back to the original
1247  *    string, replacing the relevant part of the
1248  *    original string
1249  *  - now any arrays in the original string that
1250  *    contained the replaced string may have the
1251  *    wrong length; so we have to fix that
1252  */
1253 static dbus_bool_t
1254 reader_set_basic_variable_length (DBusTypeReader       *reader,
1255                                   int                   current_type,
1256                                   const void           *value,
1257                                   const DBusTypeReader *realign_root)
1258 {
1259   dbus_bool_t retval;
1260   ReplacementBlock block;
1261   DBusTypeWriter writer;
1262
1263   _dbus_assert (realign_root != NULL);
1264
1265   retval = FALSE;
1266
1267   if (!replacement_block_init (&block, reader))
1268     return FALSE;
1269
1270   /* Write the new basic value */
1271 #if RECURSIVE_MARSHAL_WRITE_TRACE
1272   _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
1273                  &writer, _dbus_string_get_length (&block.replacement));
1274 #endif
1275   _dbus_type_writer_init_values_only (&writer,
1276                                       reader->byte_order,
1277                                       reader->type_str,
1278                                       reader->type_pos,
1279                                       &block.replacement,
1280                                       _dbus_string_get_length (&block.replacement));
1281 #if RECURSIVE_MARSHAL_WRITE_TRACE
1282   _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
1283 #endif
1284   if (!_dbus_type_writer_write_basic (&writer, current_type, value))
1285     goto out;
1286
1287   if (!replacement_block_replace (&block,
1288                                   reader,
1289                                   realign_root))
1290     goto out;
1291
1292   retval = TRUE;
1293
1294  out:
1295   replacement_block_free (&block);
1296   return retval;
1297 }
1298
1299 static void
1300 reader_set_basic_fixed_length (DBusTypeReader *reader,
1301                                int             current_type,
1302                                const void     *value)
1303 {
1304   _dbus_marshal_set_basic ((DBusString*) reader->value_str,
1305                            reader->value_pos,
1306                            current_type,
1307                            value,
1308                            reader->byte_order,
1309                            NULL, NULL);
1310 }
1311
1312 /**
1313  * Sets a new value for the basic type value pointed to by the reader,
1314  * leaving the reader valid to continue reading. Any other readers
1315  * will be invalidated if you set a variable-length type such as a
1316  * string.
1317  *
1318  * The provided realign_root is the reader to start from when
1319  * realigning the data that follows the newly-set value. The reader
1320  * parameter must point to a value below the realign_root parameter.
1321  * If the type being set is fixed-length, then realign_root may be
1322  * #NULL. Only values reachable from realign_root will be realigned,
1323  * so if your string contains other values you will need to deal with
1324  * those somehow yourself. It is OK if realign_root is the same
1325  * reader as the reader parameter, though if you aren't setting the
1326  * root it may not be such a good idea.
1327  *
1328  * @todo DBusTypeReader currently takes "const" versions of the type
1329  * and value strings, and this function modifies those strings by
1330  * casting away the const, which is of course bad if we want to get
1331  * picky. (To be truly clean you'd have an object which contained the
1332  * type and value strings and set_basic would be a method on that
1333  * object... this would also make DBusTypeReader the same thing as
1334  * DBusTypeMark. But since DBusMessage is effectively that object for
1335  * D-Bus it doesn't seem worth creating some random object.)
1336  *
1337  * @todo optimize this by only rewriting until the old and new values
1338  * are at the same alignment. Frequently this should result in only
1339  * replacing the value that's immediately at hand.
1340  *
1341  * @param reader reader indicating where to set a new value
1342  * @param value address of the value to set
1343  * @param realign_root realign from here
1344  * @returns #FALSE if not enough memory
1345  */
1346 dbus_bool_t
1347 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
1348                              const void           *value,
1349                              const DBusTypeReader *realign_root)
1350 {
1351   int current_type;
1352
1353   _dbus_assert (!reader->klass->types_only);
1354   _dbus_assert (reader->value_str == realign_root->value_str);
1355   _dbus_assert (reader->value_pos >= realign_root->value_pos);
1356
1357   current_type = _dbus_type_reader_get_current_type (reader);
1358
1359 #if RECURSIVE_MARSHAL_WRITE_TRACE
1360   _dbus_verbose ("  SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",
1361                  reader, reader->type_pos, reader->value_pos,
1362                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1363                  realign_root,
1364                  realign_root ? realign_root->value_pos : -1,
1365                  _dbus_type_to_string (current_type));
1366   _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
1367                                  _dbus_string_get_length (realign_root->value_str) -
1368                                  realign_root->value_pos);
1369 #endif
1370
1371   _dbus_assert (dbus_type_is_basic (current_type));
1372
1373   if (dbus_type_is_fixed (current_type))
1374     {
1375       reader_set_basic_fixed_length (reader, current_type, value);
1376       return TRUE;
1377     }
1378   else
1379     {
1380       _dbus_assert (realign_root != NULL);
1381       return reader_set_basic_variable_length (reader, current_type,
1382                                                value, realign_root);
1383     }
1384 }
1385
1386 /**
1387  * Recursively deletes any value pointed to by the reader, leaving the
1388  * reader valid to continue reading. Any other readers will be
1389  * invalidated.
1390  *
1391  * The provided realign_root is the reader to start from when
1392  * realigning the data that follows the newly-set value.
1393  * See _dbus_type_reader_set_basic() for more details on the
1394  * realign_root paramter.
1395  *
1396  * @todo for now this does not delete the typecodes associated with
1397  * the value, so this function should only be used for array elements.
1398  *
1399  * @param reader reader indicating where to delete a value
1400  * @param realign_root realign from here
1401  * @returns #FALSE if not enough memory
1402  */
1403 dbus_bool_t
1404 _dbus_type_reader_delete (DBusTypeReader        *reader,
1405                           const DBusTypeReader  *realign_root)
1406 {
1407   dbus_bool_t retval;
1408   ReplacementBlock block;
1409
1410   _dbus_assert (realign_root != NULL);
1411   _dbus_assert (reader->klass == &array_reader_class);
1412
1413   retval = FALSE;
1414
1415   if (!replacement_block_init (&block, reader))
1416     return FALSE;
1417
1418   if (!replacement_block_replace (&block,
1419                                   reader,
1420                                   realign_root))
1421     goto out;
1422
1423   retval = TRUE;
1424
1425  out:
1426   replacement_block_free (&block);
1427   return retval;
1428 }
1429
1430 /**
1431  * Compares two readers, which must be iterating over the same value data.
1432  * Returns #TRUE if the first parameter is further along than the second parameter.
1433  *
1434  * @param lhs left-hand-side (first) parameter
1435  * @param rhs left-hand-side (first) parameter
1436  * @returns whether lhs is greater than rhs
1437  */
1438 dbus_bool_t
1439 _dbus_type_reader_greater_than (const DBusTypeReader  *lhs,
1440                                 const DBusTypeReader  *rhs)
1441 {
1442   _dbus_assert (lhs->value_str == rhs->value_str);
1443
1444   return lhs->value_pos > rhs->value_pos;
1445 }
1446
1447 /*
1448  *
1449  *
1450  *         DBusTypeWriter
1451  *
1452  *
1453  *
1454  */
1455
1456 /**
1457  * Initialize a write iterator, which is used to write out values in
1458  * serialized D-Bus format.
1459  *
1460  * The type_pos passed in is expected to be inside an already-valid,
1461  * though potentially empty, type signature. This means that the byte
1462  * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
1463  * other valid type. #DBusTypeWriter won't enforce that the signature
1464  * is already valid (you can append the nul byte at the end if you
1465  * like), but just be aware that you need the nul byte eventually and
1466  * #DBusTypeWriter isn't going to write it for you.
1467  *
1468  * @param writer the writer to init
1469  * @param byte_order the byte order to marshal into
1470  * @param type_str the string to write typecodes into
1471  * @param type_pos where to insert typecodes
1472  * @param value_str the string to write values into
1473  * @param value_pos where to insert values
1474  *
1475  */
1476 void
1477 _dbus_type_writer_init (DBusTypeWriter *writer,
1478                         int             byte_order,
1479                         DBusString     *type_str,
1480                         int             type_pos,
1481                         DBusString     *value_str,
1482                         int             value_pos)
1483 {
1484   writer->byte_order = byte_order;
1485   writer->type_str = type_str;
1486   writer->type_pos = type_pos;
1487   writer->value_str = value_str;
1488   writer->value_pos = value_pos;
1489   writer->container_type = DBUS_TYPE_INVALID;
1490   writer->type_pos_is_expectation = FALSE;
1491   writer->enabled = TRUE;
1492
1493 #if RECURSIVE_MARSHAL_WRITE_TRACE
1494   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1495                  writer->type_str ?
1496                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1497                  "unknown");
1498 #endif
1499 }
1500
1501 /**
1502  * Initialize a write iterator, with the signature to be provided
1503  * later.
1504  *
1505  * @param writer the writer to init
1506  * @param byte_order the byte order to marshal into
1507  * @param value_str the string to write values into
1508  * @param value_pos where to insert values
1509  *
1510  */
1511 void
1512 _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer,
1513                                       int             byte_order,
1514                                       DBusString     *value_str,
1515                                       int             value_pos)
1516 {
1517   _dbus_type_writer_init (writer, byte_order,
1518                           NULL, 0, value_str, value_pos);
1519 }
1520
1521 /**
1522  * Adds type string to the writer, if it had none.
1523  *
1524  * @param writer the writer to init
1525  * @param type_str type string to add
1526  * @param type_pos type position
1527  *
1528  */
1529 void
1530 _dbus_type_writer_add_types (DBusTypeWriter *writer,
1531                              DBusString     *type_str,
1532                              int             type_pos)
1533 {
1534   if (writer->type_str == NULL) /* keeps us from using this as setter */
1535     {
1536       writer->type_str = type_str;
1537       writer->type_pos = type_pos;
1538     }
1539 }
1540
1541 /**
1542  * Removes type string from the writer.
1543  *
1544  * @param writer the writer to remove from
1545  */
1546 void
1547 _dbus_type_writer_remove_types (DBusTypeWriter *writer)
1548 {
1549   writer->type_str = NULL;
1550   writer->type_pos = -1;
1551 }
1552
1553 /**
1554  * Like _dbus_type_writer_init(), except the type string
1555  * passed in should correspond to an existing signature that
1556  * matches what you're going to write out. The writer will
1557  * check what you write vs. this existing signature.
1558  *
1559  * @param writer the writer to init
1560  * @param byte_order the byte order to marshal into
1561  * @param type_str the string with signature
1562  * @param type_pos start of signature
1563  * @param value_str the string to write values into
1564  * @param value_pos where to insert values
1565  *
1566  */
1567 void
1568 _dbus_type_writer_init_values_only (DBusTypeWriter   *writer,
1569                                     int               byte_order,
1570                                     const DBusString *type_str,
1571                                     int               type_pos,
1572                                     DBusString       *value_str,
1573                                     int               value_pos)
1574 {
1575   _dbus_type_writer_init (writer, byte_order,
1576                           (DBusString*)type_str, type_pos,
1577                           value_str, value_pos);
1578
1579   writer->type_pos_is_expectation = TRUE;
1580 }
1581
1582 static dbus_bool_t
1583 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1584                                            int             type,
1585                                            const void     *value)
1586 {
1587   if (writer->enabled)
1588     return _dbus_marshal_write_basic (writer->value_str,
1589                                       writer->value_pos,
1590                                       type,
1591                                       value,
1592                                       writer->byte_order,
1593                                       &writer->value_pos);
1594   else
1595     return TRUE;
1596 }
1597
1598 /* If our parent is an array, things are a little bit complicated.
1599  *
1600  * The parent must have a complete element type, such as
1601  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1602  * unclosed parens, or an "a" with no following type.
1603  *
1604  * To recurse, the only allowed operation is to recurse into the
1605  * first type in the element type. So for "i" you can't recurse, for
1606  * "ai" you can recurse into the array, for "(ii)" you can recurse
1607  * into the struct.
1608  *
1609  * If you recurse into the array for "ai", then you must specify
1610  * "i" for the element type of the array you recurse into.
1611  *
1612  * While inside an array at any level, we need to avoid writing to
1613  * type_str, since the type only appears once for the whole array,
1614  * it does not appear for each array element.
1615  *
1616  * While inside an array type_pos points to the expected next
1617  * typecode, rather than the next place we could write a typecode.
1618  */
1619 static void
1620 writer_recurse_init_and_check (DBusTypeWriter *writer,
1621                                int             container_type,
1622                                DBusTypeWriter *sub)
1623 {
1624   _dbus_type_writer_init (sub,
1625                           writer->byte_order,
1626                           writer->type_str,
1627                           writer->type_pos,
1628                           writer->value_str,
1629                           writer->value_pos);
1630
1631   sub->container_type = container_type;
1632
1633   if (writer->type_pos_is_expectation ||
1634       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
1635     sub->type_pos_is_expectation = TRUE;
1636   else
1637     sub->type_pos_is_expectation = FALSE;
1638
1639   sub->enabled = writer->enabled;
1640
1641 #ifndef DBUS_DISABLE_CHECKS
1642   if (writer->type_pos_is_expectation && writer->type_str)
1643     {
1644       int expected;
1645
1646       expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos);
1647
1648       if (expected != sub->container_type)
1649         {
1650           if (expected != DBUS_TYPE_INVALID)
1651             _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"
1652                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1653                                      _dbus_type_to_string (sub->container_type),
1654                                      _dbus_type_to_string (expected),
1655                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1656           else
1657             _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n"
1658                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1659                                      _dbus_type_to_string (sub->container_type),
1660                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1661           
1662           _dbus_assert_not_reached ("bad array element or variant content written");
1663         }
1664     }
1665 #endif /* DBUS_DISABLE_CHECKS */
1666
1667 #if RECURSIVE_MARSHAL_WRITE_TRACE
1668   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
1669                  writer,
1670                  _dbus_type_to_string (writer->container_type),
1671                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1672                  writer->type_str ?
1673                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1674                  "unknown",
1675                  writer->enabled);
1676   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
1677                  sub,
1678                  _dbus_type_to_string (sub->container_type),
1679                  sub->type_pos, sub->value_pos,
1680                  sub->type_pos_is_expectation,
1681                  sub->enabled);
1682 #endif
1683 }
1684
1685 static dbus_bool_t
1686 write_or_verify_typecode (DBusTypeWriter *writer,
1687                           int             typecode)
1688 {
1689   /* A subwriter inside an array or variant will have type_pos
1690    * pointing to the expected typecode; a writer not inside an array
1691    * or variant has type_pos pointing to the next place to insert a
1692    * typecode.
1693    */
1694 #if RECURSIVE_MARSHAL_WRITE_TRACE
1695   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
1696                  writer, writer->type_pos,
1697                  writer->type_str ?
1698                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1699                  "unknown",
1700                  writer->enabled);
1701 #endif
1702
1703   if (writer->type_str == NULL)
1704     return TRUE;
1705
1706   if (writer->type_pos_is_expectation)
1707     {
1708 #ifndef DBUS_DISABLE_CHECKS
1709       {
1710         int expected;
1711
1712         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1713
1714         if (expected != typecode)
1715           {
1716             if (expected != DBUS_TYPE_INVALID)
1717               _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"
1718                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1719                                        _dbus_type_to_string (expected), _dbus_type_to_string (typecode),
1720                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1721             else
1722               _dbus_warn_check_failed ("Array or variant type wasn't expecting any more values to be written into it, but a value %s was written.\n"
1723                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1724                                        _dbus_type_to_string (typecode),
1725                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1726             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1727           }
1728       }
1729 #endif /* DBUS_DISABLE_CHECKS */
1730
1731       /* if immediately inside an array we'd always be appending an element,
1732        * so the expected type doesn't change; if inside a struct or something
1733        * below an array, we need to move through said struct or something.
1734        */
1735       if (writer->container_type != DBUS_TYPE_ARRAY)
1736         writer->type_pos += 1;
1737     }
1738   else
1739     {
1740       if (!_dbus_string_insert_byte (writer->type_str,
1741                                      writer->type_pos,
1742                                      typecode))
1743         return FALSE;
1744
1745       writer->type_pos += 1;
1746     }
1747
1748 #if RECURSIVE_MARSHAL_WRITE_TRACE
1749   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1750                  writer, writer->type_pos,
1751                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1752 #endif
1753
1754   return TRUE;
1755 }
1756
1757 static dbus_bool_t
1758 writer_recurse_struct_or_dict_entry (DBusTypeWriter   *writer,
1759                                      int               begin_char,
1760                                      const DBusString *contained_type,
1761                                      int               contained_type_start,
1762                                      int               contained_type_len,
1763                                      DBusTypeWriter   *sub)
1764 {
1765   /* FIXME right now contained_type is ignored; we could probably
1766    * almost trivially fix the code so if it's present we
1767    * write it out and then set type_pos_is_expectation
1768    */
1769
1770   /* Ensure that we'll be able to add alignment padding and the typecode */
1771   if (writer->enabled)
1772     {
1773       if (!_dbus_string_alloc_space (sub->value_str, 8))
1774         return FALSE;
1775     }
1776
1777   if (!write_or_verify_typecode (sub, begin_char))
1778     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1779
1780   if (writer->enabled)
1781     {
1782       if (!_dbus_string_insert_bytes (sub->value_str,
1783                                       sub->value_pos,
1784                                       _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1785                                       '\0'))
1786         _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1787       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1788     }
1789
1790   return TRUE;
1791 }
1792
1793
1794 static dbus_bool_t
1795 writer_recurse_array (DBusTypeWriter   *writer,
1796                       const DBusString *contained_type,
1797                       int               contained_type_start,
1798                       int               contained_type_len,
1799                       DBusTypeWriter   *sub,
1800                       dbus_bool_t       is_array_append)
1801 {
1802   dbus_uint32_t value = 0;
1803   int alignment;
1804   int aligned;
1805
1806 #ifndef DBUS_DISABLE_CHECKS
1807   if (writer->container_type == DBUS_TYPE_ARRAY &&
1808       writer->type_str)
1809     {
1810       if (!_dbus_string_equal_substring (contained_type,
1811                                          contained_type_start,
1812                                          contained_type_len,
1813                                          writer->type_str,
1814                                          writer->u.array.element_type_pos + 1))
1815         {
1816           _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1817                                    _dbus_string_get_const_data_len (contained_type,
1818                                                                     contained_type_start,
1819                                                                     contained_type_len));
1820           _dbus_assert_not_reached ("incompatible type for child array");
1821         }
1822     }
1823 #endif /* DBUS_DISABLE_CHECKS */
1824
1825   if (writer->enabled && !is_array_append)
1826     {
1827       /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1828        * before array values
1829        */
1830       if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1831         return FALSE;
1832     }
1833
1834   if (writer->type_str != NULL)
1835     {
1836       sub->type_pos += 1; /* move to point to the element type, since type_pos
1837                            * should be the expected type for further writes
1838                            */
1839       sub->u.array.element_type_pos = sub->type_pos;
1840     }
1841
1842   if (!writer->type_pos_is_expectation)
1843     {
1844       /* sub is a toplevel/outermost array so we need to write the type data */
1845
1846       /* alloc space for array typecode, element signature */
1847       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1848         return FALSE;
1849
1850       if (!_dbus_string_insert_byte (writer->type_str,
1851                                      writer->type_pos,
1852                                      DBUS_TYPE_ARRAY))
1853         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1854
1855       if (!_dbus_string_copy_len (contained_type,
1856                                   contained_type_start, contained_type_len,
1857                                   sub->type_str,
1858                                   sub->u.array.element_type_pos))
1859         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1860     }
1861
1862   if (writer->type_str != NULL)
1863     {
1864       /* If the parent is an array, we hold type_pos pointing at the array element type;
1865        * otherwise advance it to reflect the array value we just recursed into
1866        */
1867       if (writer->container_type != DBUS_TYPE_ARRAY)
1868         writer->type_pos += 1 + contained_type_len;
1869       else
1870         _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1871     }
1872
1873   if (writer->enabled)
1874     {
1875       /* Write (or jump over, if is_array_append) the length */
1876       sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1877
1878       if (is_array_append)
1879         {
1880           sub->value_pos += 4;
1881         }
1882       else
1883         {
1884           if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1885                                                           &value))
1886             _dbus_assert_not_reached ("should not have failed to insert array len");
1887         }
1888
1889       _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1890
1891       /* Write alignment padding for array elements
1892        * Note that we write the padding *even for empty arrays*
1893        * to avoid wonky special cases
1894        */
1895       alignment = element_type_get_alignment (contained_type, contained_type_start);
1896
1897       aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1898       if (aligned != sub->value_pos)
1899         {
1900           if (!is_array_append)
1901             {
1902               if (!_dbus_string_insert_bytes (sub->value_str,
1903                                               sub->value_pos,
1904                                               aligned - sub->value_pos,
1905                                               '\0'))
1906                 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1907             }
1908
1909           sub->value_pos = aligned;
1910         }
1911
1912       sub->u.array.start_pos = sub->value_pos;
1913
1914       if (is_array_append)
1915         {
1916           dbus_uint32_t len;
1917
1918           _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==
1919                         (unsigned) sub->u.array.len_pos);
1920           len = _dbus_unpack_uint32 (sub->byte_order,
1921                                      _dbus_string_get_const_data_len (sub->value_str,
1922                                                                       sub->u.array.len_pos,
1923                                                                       4));
1924
1925           sub->value_pos += len;
1926         }
1927     }
1928   else
1929     {
1930       /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
1931       sub->u.array.len_pos = -1;
1932       sub->u.array.start_pos = sub->value_pos;
1933     }
1934
1935   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1936   _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
1937
1938 #if RECURSIVE_MARSHAL_WRITE_TRACE
1939       _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
1940                      sub->type_str ?
1941                      _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
1942                      "unknown",
1943                      sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
1944 #endif
1945
1946   return TRUE;
1947 }
1948
1949 /* Variant value will normally have:
1950  *   1 byte signature length not including nul
1951  *   signature typecodes (nul terminated)
1952  *   padding to alignment of contained type
1953  *   body according to signature
1954  *
1955  * The signature string can only have a single type
1956  * in it but that type may be complex/recursive.
1957  *
1958  * So a typical variant type with the integer 3 will have these
1959  * octets:
1960  *   0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3
1961  *
1962  * The main world of hurt for writing out a variant is that the type
1963  * string is the same string as the value string. Which means
1964  * inserting to the type string will move the value_pos; and it means
1965  * that inserting to the type string could break type alignment.
1966  */
1967 static dbus_bool_t
1968 writer_recurse_variant (DBusTypeWriter   *writer,
1969                         const DBusString *contained_type,
1970                         int               contained_type_start,
1971                         int               contained_type_len,
1972                         DBusTypeWriter   *sub)
1973 {
1974   int contained_alignment;
1975   
1976   if (writer->enabled)
1977     {
1978       /* Allocate space for the worst case, which is 1 byte sig
1979        * length, nul byte at end of sig, and 7 bytes padding to
1980        * 8-boundary.
1981        */
1982       if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1983         return FALSE;
1984     }
1985
1986   /* write VARIANT typecode to the parent's type string */
1987   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1988     return FALSE;
1989
1990   /* If not enabled, mark that we have no type_str anymore ... */
1991
1992   if (!writer->enabled)
1993     {
1994       sub->type_str = NULL;
1995       sub->type_pos = -1;
1996
1997       return TRUE;
1998     }
1999
2000   /* If we're enabled then continue ... */
2001
2002   if (!_dbus_string_insert_byte (sub->value_str,
2003                                  sub->value_pos,
2004                                  contained_type_len))
2005     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
2006
2007   sub->value_pos += 1;
2008
2009   /* Here we switch over to the expected type sig we're about to write */
2010   sub->type_str = sub->value_str;
2011   sub->type_pos = sub->value_pos;
2012
2013   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
2014                               sub->value_str, sub->value_pos))
2015     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
2016
2017   sub->value_pos += contained_type_len;
2018
2019   if (!_dbus_string_insert_byte (sub->value_str,
2020                                  sub->value_pos,
2021                                  DBUS_TYPE_INVALID))
2022     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
2023
2024   sub->value_pos += 1;
2025
2026   contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));
2027   
2028   if (!_dbus_string_insert_bytes (sub->value_str,
2029                                   sub->value_pos,
2030                                   _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,
2031                                   '\0'))
2032     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
2033   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
2034
2035   return TRUE;
2036 }
2037
2038 static dbus_bool_t
2039 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
2040                                          int               container_type,
2041                                          const DBusString *contained_type,
2042                                          int               contained_type_start,
2043                                          int               contained_type_len,
2044                                          DBusTypeWriter   *sub,
2045                                          dbus_bool_t       is_array_append)
2046 {
2047   writer_recurse_init_and_check (writer, container_type, sub);
2048
2049   switch (container_type)
2050     {
2051     case DBUS_TYPE_STRUCT:
2052       return writer_recurse_struct_or_dict_entry (writer,
2053                                                   DBUS_STRUCT_BEGIN_CHAR,
2054                                                   contained_type,
2055                                                   contained_type_start, contained_type_len,
2056                                                   sub);
2057       break;
2058     case DBUS_TYPE_DICT_ENTRY:
2059       return writer_recurse_struct_or_dict_entry (writer,
2060                                                   DBUS_DICT_ENTRY_BEGIN_CHAR,
2061                                                   contained_type,
2062                                                   contained_type_start, contained_type_len,
2063                                                   sub);
2064       break;
2065     case DBUS_TYPE_ARRAY:
2066       return writer_recurse_array (writer,
2067                                    contained_type, contained_type_start, contained_type_len,
2068                                    sub, is_array_append);
2069       break;
2070     case DBUS_TYPE_VARIANT:
2071       return writer_recurse_variant (writer,
2072                                      contained_type, contained_type_start, contained_type_len,
2073                                      sub);
2074       break;
2075     default:
2076       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
2077       return FALSE;
2078       break;
2079     }
2080 }
2081
2082 /**
2083  * Opens a new container and writes out the initial information for that container.
2084  *
2085  * @param writer the writer
2086  * @param container_type the type of the container to open
2087  * @param contained_type the array element type or variant content type
2088  * @param contained_type_start position to look for the type
2089  * @param sub the new sub-writer to write container contents
2090  * @returns #FALSE if no memory
2091  */
2092 dbus_bool_t
2093 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
2094                            int               container_type,
2095                            const DBusString *contained_type,
2096                            int               contained_type_start,
2097                            DBusTypeWriter   *sub)
2098 {
2099   int contained_type_len;
2100
2101   if (contained_type)
2102     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2103   else
2104     contained_type_len = 0;
2105
2106   return _dbus_type_writer_recurse_contained_len (writer, container_type,
2107                                                   contained_type,
2108                                                   contained_type_start,
2109                                                   contained_type_len,
2110                                                   sub,
2111                                                   FALSE);
2112 }
2113
2114 /**
2115  * Append to an existing array. Essentially, the writer will read an
2116  * existing length at the write location; jump over that length; and
2117  * write new fields. On unrecurse(), the existing length will be
2118  * updated.
2119  *
2120  * @param writer the writer
2121  * @param contained_type element type
2122  * @param contained_type_start position of element type
2123  * @param sub the subwriter to init
2124  * @returns #FALSE if no memory
2125  */
2126 dbus_bool_t
2127 _dbus_type_writer_append_array (DBusTypeWriter   *writer,
2128                                 const DBusString *contained_type,
2129                                 int               contained_type_start,
2130                                 DBusTypeWriter   *sub)
2131 {
2132   int contained_type_len;
2133
2134   if (contained_type)
2135     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2136   else
2137     contained_type_len = 0;
2138
2139   return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
2140                                                   contained_type,
2141                                                   contained_type_start,
2142                                                   contained_type_len,
2143                                                   sub,
2144                                                   TRUE);
2145 }
2146
2147 static int
2148 writer_get_array_len (DBusTypeWriter *writer)
2149 {
2150   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
2151   return writer->value_pos - writer->u.array.start_pos;
2152 }
2153
2154 /**
2155  * Closes a container created by _dbus_type_writer_recurse()
2156  * and writes any additional information to the values block.
2157  *
2158  * @param writer the writer
2159  * @param sub the sub-writer created by _dbus_type_writer_recurse()
2160  * @returns #FALSE if no memory
2161  */
2162 dbus_bool_t
2163 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
2164                              DBusTypeWriter *sub)
2165 {
2166   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
2167   _dbus_assert (!writer->type_pos_is_expectation ||
2168                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
2169
2170 #if RECURSIVE_MARSHAL_WRITE_TRACE
2171   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2172                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2173                  _dbus_type_to_string (writer->container_type));
2174   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2175                  sub, sub->type_pos, sub->value_pos,
2176                  sub->type_pos_is_expectation,
2177                  _dbus_type_to_string (sub->container_type));
2178 #endif
2179
2180   if (sub->container_type == DBUS_TYPE_STRUCT)
2181     {
2182       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
2183         return FALSE;
2184     }
2185   else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
2186     {
2187       if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
2188         return FALSE;
2189     }
2190   else if (sub->container_type == DBUS_TYPE_ARRAY)
2191     {
2192       if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
2193         {
2194           dbus_uint32_t len;
2195
2196           /* Set the array length */
2197           len = writer_get_array_len (sub);
2198           _dbus_marshal_set_uint32 (sub->value_str,
2199                                     sub->u.array.len_pos,
2200                                     len,
2201                                     sub->byte_order);
2202 #if RECURSIVE_MARSHAL_WRITE_TRACE
2203           _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
2204                          len, sub->u.array.len_pos);
2205 #endif
2206         }
2207 #if RECURSIVE_MARSHAL_WRITE_TRACE
2208       else
2209         {
2210           _dbus_verbose ("    not filling in sub array len because we were disabled when we passed the len\n");
2211         }
2212 #endif
2213     }
2214
2215   /* Now get type_pos right for the parent writer. Here are the cases:
2216    *
2217    * Cases !writer->type_pos_is_expectation:
2218    *   (in these cases we want to update to the new insertion point)
2219    *
2220    * - if we recursed into a STRUCT then we didn't know in advance
2221    *   what the types in the struct would be; so we have to fill in
2222    *   that information now.
2223    *       writer->type_pos = sub->type_pos
2224    *
2225    * - if we recursed into anything else, we knew the full array
2226    *   type, or knew the single typecode marking VARIANT, so
2227    *   writer->type_pos is already correct.
2228    *       writer->type_pos should remain as-is
2229    *
2230    * - note that the parent is never an ARRAY or VARIANT, if it were
2231    *   then type_pos_is_expectation would be TRUE. The parent
2232    *   is thus known to be a toplevel or STRUCT.
2233    *
2234    * Cases where writer->type_pos_is_expectation:
2235    *   (in these cases we want to update to next expected type to write)
2236    *
2237    * - we recursed from STRUCT into STRUCT and we didn't increment
2238    *   type_pos in the parent just to stay consistent with the
2239    *   !writer->type_pos_is_expectation case (though we could
2240    *   special-case this in recurse_struct instead if we wanted)
2241    *       writer->type_pos = sub->type_pos
2242    *
2243    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
2244    *   for parent should have been incremented already
2245    *       writer->type_pos should remain as-is
2246    *
2247    * - we recursed from ARRAY into a sub-element, so type_pos in the
2248    *   parent is the element type and should remain the element type
2249    *   for the benefit of the next child element
2250    *       writer->type_pos should remain as-is
2251    *
2252    * - we recursed from VARIANT into its value, so type_pos in the
2253    *   parent makes no difference since there's only one value
2254    *   and we just finished writing it and won't use type_pos again
2255    *       writer->type_pos should remain as-is
2256    *
2257    *
2258    * For all these, DICT_ENTRY is the same as STRUCT
2259    */
2260   if (writer->type_str != NULL)
2261     {
2262       if ((sub->container_type == DBUS_TYPE_STRUCT ||
2263            sub->container_type == DBUS_TYPE_DICT_ENTRY) &&
2264           (writer->container_type == DBUS_TYPE_STRUCT ||
2265            writer->container_type == DBUS_TYPE_DICT_ENTRY ||
2266            writer->container_type == DBUS_TYPE_INVALID))
2267         {
2268           /* Advance the parent to the next struct field */
2269           writer->type_pos = sub->type_pos;
2270         }
2271     }
2272
2273   writer->value_pos = sub->value_pos;
2274
2275 #if RECURSIVE_MARSHAL_WRITE_TRACE
2276   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
2277                  writer, writer->type_pos, writer->value_pos,
2278                  writer->type_str ?
2279                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
2280                  "unknown");
2281 #endif
2282
2283   return TRUE;
2284 }
2285
2286 /**
2287  * Writes out a basic type.
2288  *
2289  * @param writer the writer
2290  * @param type the type to write
2291  * @param value the address of the value to write
2292  * @returns #FALSE if no memory
2293  */
2294 dbus_bool_t
2295 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
2296                                int             type,
2297                                const void     *value)
2298 {
2299   dbus_bool_t retval;
2300
2301   /* First ensure that our type realloc will succeed */
2302   if (!writer->type_pos_is_expectation && writer->type_str != NULL)
2303     {
2304       if (!_dbus_string_alloc_space (writer->type_str, 1))
2305         return FALSE;
2306     }
2307
2308   retval = FALSE;
2309
2310   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
2311     goto out;
2312
2313   if (!write_or_verify_typecode (writer, type))
2314     _dbus_assert_not_reached ("failed to write typecode after prealloc");
2315
2316   retval = TRUE;
2317
2318  out:
2319 #if RECURSIVE_MARSHAL_WRITE_TRACE
2320   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
2321                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2322                  writer->enabled);
2323 #endif
2324
2325   return retval;
2326 }
2327
2328 /**
2329  * Writes a block of fixed-length basic values, i.e. those that are
2330  * both dbus_type_is_fixed() and _dbus_type_is_basic(). The block
2331  * must be written inside an array.
2332  *
2333  * The value parameter should be the address of said array of values,
2334  * so e.g. if it's an array of double, pass in "const double**"
2335  *
2336  * @param writer the writer
2337  * @param element_type type of stuff in the array
2338  * @param value address of the array
2339  * @param n_elements number of elements in the array
2340  * @returns #FALSE if no memory
2341  */
2342 dbus_bool_t
2343 _dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,
2344                                      int                    element_type,
2345                                      const void            *value,
2346                                      int                    n_elements)
2347 {
2348   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
2349   _dbus_assert (dbus_type_is_fixed (element_type));
2350   _dbus_assert (writer->type_pos_is_expectation);
2351   _dbus_assert (n_elements >= 0);
2352
2353 #if RECURSIVE_MARSHAL_WRITE_TRACE
2354   _dbus_verbose ("  type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",
2355                  writer, writer->type_pos, writer->value_pos, n_elements);
2356 #endif
2357
2358   if (!write_or_verify_typecode (writer, element_type))
2359     _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
2360
2361   if (writer->enabled)
2362     {
2363       if (!_dbus_marshal_write_fixed_multi (writer->value_str,
2364                                             writer->value_pos,
2365                                             element_type,
2366                                             value,
2367                                             n_elements,
2368                                             writer->byte_order,
2369                                             &writer->value_pos))
2370         return FALSE;
2371     }
2372
2373 #if RECURSIVE_MARSHAL_WRITE_TRACE
2374   _dbus_verbose ("  type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",
2375                  writer, writer->type_pos, writer->value_pos, n_elements);
2376 #endif
2377
2378   return TRUE;
2379 }
2380
2381 static void
2382 enable_if_after (DBusTypeWriter       *writer,
2383                  DBusTypeReader       *reader,
2384                  const DBusTypeReader *start_after)
2385 {
2386   if (start_after)
2387     {
2388       if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))
2389         {
2390           _dbus_type_writer_set_enabled (writer, TRUE);
2391 #if RECURSIVE_MARSHAL_WRITE_TRACE
2392           _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",
2393                          writer, writer->value_pos, reader->value_pos, start_after->value_pos);
2394 #endif
2395         }
2396
2397       _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||
2398                     (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));
2399     }
2400 }
2401
2402 static dbus_bool_t
2403 append_fixup (DBusList               **fixups,
2404               const DBusArrayLenFixup *fixup)
2405 {
2406   DBusArrayLenFixup *f;
2407
2408   f = dbus_new (DBusArrayLenFixup, 1);
2409   if (f == NULL)
2410     return FALSE;
2411
2412   *f = *fixup;
2413
2414   if (!_dbus_list_append (fixups, f))
2415     {
2416       dbus_free (f);
2417       return FALSE;
2418     }
2419
2420   _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader);
2421   _dbus_assert (f->new_len == fixup->new_len);
2422
2423   return TRUE;
2424 }
2425
2426 /* This loop is trivial if you ignore all the start_after nonsense,
2427  * so if you're trying to figure it out, start by ignoring that
2428  */
2429 static dbus_bool_t
2430 writer_write_reader_helper (DBusTypeWriter       *writer,
2431                             DBusTypeReader       *reader,
2432                             const DBusTypeReader *start_after,
2433                             int                   start_after_new_pos,
2434                             int                   start_after_new_len,
2435                             DBusList            **fixups,
2436                             dbus_bool_t           inside_start_after)
2437 {
2438   int current_type;
2439
2440   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
2441     {
2442       if (dbus_type_is_container (current_type))
2443         {
2444           DBusTypeReader subreader;
2445           DBusTypeWriter subwriter;
2446           const DBusString *sig_str;
2447           int sig_start;
2448           int sig_len;
2449           dbus_bool_t enabled_at_recurse;
2450           dbus_bool_t past_start_after;
2451           int reader_array_len_pos;
2452           int reader_array_start_pos;
2453           dbus_bool_t this_is_start_after;
2454
2455           /* type_pos is checked since e.g. in a struct the struct
2456            * and its first field have the same value_pos.
2457            * type_str will differ in reader/start_after for variants
2458            * where type_str is inside the value_str
2459            */
2460           if (!inside_start_after && start_after &&
2461               reader->value_pos == start_after->value_pos &&
2462               reader->type_str == start_after->type_str &&
2463               reader->type_pos == start_after->type_pos)
2464             this_is_start_after = TRUE;
2465           else
2466             this_is_start_after = FALSE;
2467
2468           _dbus_type_reader_recurse (reader, &subreader);
2469
2470           if (current_type == DBUS_TYPE_ARRAY)
2471             {
2472               reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);
2473               reader_array_start_pos = subreader.u.array.start_pos;
2474             }
2475           else
2476             {
2477               /* quiet gcc */
2478               reader_array_len_pos = -1;
2479               reader_array_start_pos = -1;
2480             }
2481
2482           _dbus_type_reader_get_signature (&subreader, &sig_str,
2483                                            &sig_start, &sig_len);
2484
2485 #if RECURSIVE_MARSHAL_WRITE_TRACE
2486           _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n",
2487                          _dbus_type_to_string (current_type),
2488                          reader->value_pos,
2489                          subreader.value_pos,
2490                          writer->value_pos,
2491                          start_after ? start_after->value_pos : -1,
2492                          _dbus_string_get_length (writer->value_str),
2493                          inside_start_after, this_is_start_after);
2494 #endif
2495
2496           if (!inside_start_after && !this_is_start_after)
2497             enable_if_after (writer, &subreader, start_after);
2498           enabled_at_recurse = writer->enabled;
2499           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
2500                                                         sig_str, sig_start, sig_len,
2501                                                         &subwriter, FALSE))
2502             goto oom;
2503
2504 #if RECURSIVE_MARSHAL_WRITE_TRACE
2505           _dbus_verbose ("recursed into subwriter at %d write target len %d\n",
2506                          subwriter.value_pos,
2507                          _dbus_string_get_length (subwriter.value_str));
2508 #endif
2509
2510           if (!writer_write_reader_helper (&subwriter, &subreader, start_after,
2511                                            start_after_new_pos, start_after_new_len,
2512                                            fixups,
2513                                            inside_start_after ||
2514                                            this_is_start_after))
2515             goto oom;
2516
2517 #if RECURSIVE_MARSHAL_WRITE_TRACE
2518           _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d  write target len %d\n",
2519                          _dbus_type_to_string (current_type),
2520                          subreader.value_pos,
2521                          writer->value_pos,
2522                          subwriter.value_pos,
2523                          _dbus_string_get_length (writer->value_str));
2524 #endif
2525
2526           if (!inside_start_after && !this_is_start_after)
2527             enable_if_after (writer, &subreader, start_after);
2528           past_start_after = writer->enabled;
2529           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
2530             goto oom;
2531
2532           /* If we weren't enabled when we recursed, we didn't
2533            * write an array len; if we passed start_after
2534            * somewhere inside the array, then we need to generate
2535            * a fixup.
2536            */
2537           if (start_after != NULL &&
2538               !enabled_at_recurse && past_start_after &&
2539               current_type == DBUS_TYPE_ARRAY &&
2540               fixups != NULL)
2541             {
2542               DBusArrayLenFixup fixup;
2543               int bytes_written_after_start_after;
2544               int bytes_before_start_after;
2545               int old_len;
2546
2547               /* this subwriter access is moderately unkosher since we
2548                * already unrecursed, but it works as long as unrecurse
2549                * doesn't break us on purpose
2550                */
2551               bytes_written_after_start_after = writer_get_array_len (&subwriter);
2552
2553               bytes_before_start_after =
2554                 start_after->value_pos - reader_array_start_pos;
2555
2556               fixup.len_pos_in_reader = reader_array_len_pos;
2557               fixup.new_len =
2558                 bytes_before_start_after +
2559                 start_after_new_len +
2560                 bytes_written_after_start_after;
2561
2562               _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) ==
2563                             (unsigned) fixup.len_pos_in_reader);
2564
2565               old_len = _dbus_unpack_uint32 (reader->byte_order,
2566                                              _dbus_string_get_const_data_len (reader->value_str,
2567                                                                               fixup.len_pos_in_reader, 4));
2568
2569               if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))
2570                 goto oom;
2571
2572 #if RECURSIVE_MARSHAL_WRITE_TRACE
2573               _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n",
2574                              fixup.len_pos_in_reader,
2575                              fixup.new_len,
2576                              reader_array_start_pos,
2577                              start_after->value_pos,
2578                              bytes_before_start_after,
2579                              start_after_new_len,
2580                              bytes_written_after_start_after);
2581 #endif
2582             }
2583         }
2584       else
2585         {
2586           DBusBasicValue val;
2587
2588           _dbus_assert (dbus_type_is_basic (current_type));
2589
2590 #if RECURSIVE_MARSHAL_WRITE_TRACE
2591           _dbus_verbose ("Reading basic value %s at %d\n",
2592                          _dbus_type_to_string (current_type),
2593                          reader->value_pos);
2594 #endif
2595
2596           _dbus_type_reader_read_basic (reader, &val);
2597
2598 #if RECURSIVE_MARSHAL_WRITE_TRACE
2599           _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",
2600                          _dbus_type_to_string (current_type),
2601                          writer->value_pos,
2602                          _dbus_string_get_length (writer->value_str),
2603                          inside_start_after);
2604 #endif
2605           if (!inside_start_after)
2606             enable_if_after (writer, reader, start_after);
2607           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
2608             goto oom;
2609 #if RECURSIVE_MARSHAL_WRITE_TRACE
2610           _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",
2611                          _dbus_type_to_string (current_type),
2612                          writer->value_pos,
2613                          _dbus_string_get_length (writer->value_str));
2614 #endif
2615         }
2616
2617       _dbus_type_reader_next (reader);
2618     }
2619
2620   return TRUE;
2621
2622  oom:
2623   if (fixups)
2624     apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */
2625
2626   return FALSE;
2627 }
2628
2629 /**
2630  * Iterate through all values in the given reader, writing a copy of
2631  * each value to the writer.  The reader will be moved forward to its
2632  * end position.
2633  *
2634  * If a reader start_after is provided, it should be a reader for the
2635  * same data as the reader to be written. Only values occurring after
2636  * the value pointed to by start_after will be written to the writer.
2637  *
2638  * If start_after is provided, then the copy of the reader will be
2639  * partial. This means that array lengths will not have been copied.
2640  * The assumption is that you wrote a new version of the value at
2641  * start_after to the writer. You have to pass in the start position
2642  * and length of the new value. (If you are deleting the value
2643  * at start_after, pass in 0 for the length.)
2644  *
2645  * If the fixups parameter is non-#NULL, then any array length that
2646  * was read but not written due to start_after will be provided
2647  * as a #DBusArrayLenFixup. The fixup contains the position of the
2648  * array length in the source data, and the correct array length
2649  * assuming you combine the source data before start_after with
2650  * the written data at start_after and beyond.
2651  *
2652  * @param writer the writer to copy to
2653  * @param reader the reader to copy from
2654  * @param start_after #NULL or a reader showing where to start
2655  * @param start_after_new_pos the position of start_after equivalent in the target data
2656  * @param start_after_new_len the length of start_after equivalent in the target data
2657  * @param fixups list to append #DBusArrayLenFixup if the write was partial
2658  * @returns #FALSE if no memory
2659  */
2660 dbus_bool_t
2661 _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,
2662                                         DBusTypeReader       *reader,
2663                                         const DBusTypeReader *start_after,
2664                                         int                   start_after_new_pos,
2665                                         int                   start_after_new_len,
2666                                         DBusList            **fixups)
2667 {
2668   DBusTypeWriter orig;
2669   int orig_type_len;
2670   int orig_value_len;
2671   int new_bytes;
2672   int orig_enabled;
2673
2674   orig = *writer;
2675   orig_type_len = _dbus_string_get_length (writer->type_str);
2676   orig_value_len = _dbus_string_get_length (writer->value_str);
2677   orig_enabled = writer->enabled;
2678
2679   if (start_after)
2680     _dbus_type_writer_set_enabled (writer, FALSE);
2681
2682   if (!writer_write_reader_helper (writer, reader, start_after,
2683                                    start_after_new_pos,
2684                                    start_after_new_len,
2685                                    fixups, FALSE))
2686     goto oom;
2687
2688   _dbus_type_writer_set_enabled (writer, orig_enabled);
2689   return TRUE;
2690
2691  oom:
2692   if (!writer->type_pos_is_expectation)
2693     {
2694       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
2695       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
2696     }
2697   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
2698   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
2699
2700   *writer = orig;
2701
2702   return FALSE;
2703 }
2704
2705 /**
2706  * Iterate through all values in the given reader, writing a copy of
2707  * each value to the writer.  The reader will be moved forward to its
2708  * end position.
2709  *
2710  * @param writer the writer to copy to
2711  * @param reader the reader to copy from
2712  * @returns #FALSE if no memory
2713  */
2714 dbus_bool_t
2715 _dbus_type_writer_write_reader (DBusTypeWriter       *writer,
2716                                 DBusTypeReader       *reader)
2717 {
2718   return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
2719 }
2720
2721 /**
2722  * If disabled, a writer can still be iterated forward and recursed/unrecursed
2723  * but won't write any values. Types will still be written unless the
2724  * writer is a "values only" writer, because the writer needs access to
2725  * a valid signature to be able to iterate.
2726  *
2727  * @param writer the type writer
2728  * @param enabled #TRUE if values should be written
2729  */
2730 void
2731 _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,
2732                                dbus_bool_t       enabled)
2733 {
2734   writer->enabled = enabled != FALSE;
2735 }
2736
2737 /** @} */ /* end of DBusMarshal group */
2738
2739 /* tests in dbus-marshal-recursive-util.c */