D-Bus  1.4.10
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-marshal-recursive.h"
26 #include "dbus-marshal-basic.h"
27 #include "dbus-signature.h"
28 #include "dbus-internals.h"
29 
36 #define RECURSIVE_MARSHAL_READ_TRACE 0
37 
39 #define RECURSIVE_MARSHAL_WRITE_TRACE 0
40 
41 static void
42 free_fixups (DBusList **fixups)
43 {
44  DBusList *link;
45 
46  link = _dbus_list_get_first_link (fixups);
47  while (link != NULL)
48  {
49  DBusList *next;
50 
51  next = _dbus_list_get_next_link (fixups, link);
52 
53  dbus_free (link->data);
54  _dbus_list_free_link (link);
55 
56  link = next;
57  }
58 
59  *fixups = NULL;
60 }
61 
62 static void
63 apply_and_free_fixups (DBusList **fixups,
64  DBusTypeReader *reader)
65 {
66  DBusList *link;
67 
68 #if RECURSIVE_MARSHAL_WRITE_TRACE
69  if (*fixups)
70  _dbus_verbose (" %d FIXUPS to apply\n",
71  _dbus_list_get_length (fixups));
72 #endif
73 
74  link = _dbus_list_get_first_link (fixups);
75  while (link != NULL)
76  {
77  DBusList *next;
78 
79  next = _dbus_list_get_next_link (fixups, link);
80 
81  if (reader)
82  {
84 
85  f = link->data;
86 
87 #if RECURSIVE_MARSHAL_WRITE_TRACE
88  _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",
89  reader, f->len_pos_in_reader, f->new_len,
92  reader->byte_order, NULL));
93 #endif
94 
97  f->new_len,
98  reader->byte_order);
99  }
100 
101  dbus_free (link->data);
102  _dbus_list_free_link (link);
103 
104  link = next;
105  }
106 
107  *fixups = NULL;
108 }
109 
114 {
115  const char *name;
116  int id;
118  void (* recurse) (DBusTypeReader *sub,
119  DBusTypeReader *parent);
121  void (* next) (DBusTypeReader *reader,
122  int current_type);
123 };
124 
125 static int
126 element_type_get_alignment (const DBusString *str,
127  int pos)
128 {
130 }
131 
132 static void
133 reader_init (DBusTypeReader *reader,
134  int byte_order,
135  const DBusString *type_str,
136  int type_pos,
137  const DBusString *value_str,
138  int value_pos)
139 {
140  reader->byte_order = byte_order;
141  reader->finished = FALSE;
142  reader->type_str = type_str;
143  reader->type_pos = type_pos;
144  reader->value_str = value_str;
145  reader->value_pos = value_pos;
146 }
147 
148 static void
149 base_reader_recurse (DBusTypeReader *sub,
150  DBusTypeReader *parent)
151 {
152  /* point subreader at the same place as parent */
153  reader_init (sub,
154  parent->byte_order,
155  parent->type_str,
156  parent->type_pos,
157  parent->value_str,
158  parent->value_pos);
159 }
160 
161 static void
162 struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub,
163  DBusTypeReader *parent)
164 {
165  base_reader_recurse (sub, parent);
166 
168  sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR ||
171 
172  sub->type_pos += 1;
173 }
174 
175 static void
176 struct_or_dict_entry_reader_recurse (DBusTypeReader *sub,
177  DBusTypeReader *parent)
178 {
179  struct_or_dict_entry_types_only_reader_recurse (sub, parent);
180 
181  /* struct and dict entry have 8 byte alignment */
182  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
183 }
184 
185 static void
186 array_types_only_reader_recurse (DBusTypeReader *sub,
187  DBusTypeReader *parent)
188 {
189  base_reader_recurse (sub, parent);
190 
191  /* point type_pos at the array element type */
192  sub->type_pos += 1;
193 
194  /* Init with values likely to crash things if misused */
195  sub->u.array.start_pos = _DBUS_INT_MAX;
196  sub->array_len_offset = 7;
197 }
198 
201 #define ARRAY_READER_LEN_POS(reader) \
202  ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4)
203 
204 static int
205 array_reader_get_array_len (const DBusTypeReader *reader)
206 {
207  dbus_uint32_t array_len;
208  int len_pos;
209 
210  len_pos = ARRAY_READER_LEN_POS (reader);
211 
212  _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos);
213  array_len = _dbus_unpack_uint32 (reader->byte_order,
214  _dbus_string_get_const_data_len (reader->value_str, len_pos, 4));
215 
216 #if RECURSIVE_MARSHAL_READ_TRACE
217  _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n",
218  reader, len_pos, array_len, reader->array_len_offset);
219 #endif
220 
221  _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
222 
223  return array_len;
224 }
225 
226 static void
227 array_reader_recurse (DBusTypeReader *sub,
228  DBusTypeReader *parent)
229 {
230  int alignment;
231  int len_pos;
232 
233  array_types_only_reader_recurse (sub, parent);
234 
235  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
236 
237  len_pos = sub->value_pos;
238 
239  sub->value_pos += 4; /* for the length */
240 
241  alignment = element_type_get_alignment (sub->type_str,
242  sub->type_pos);
243 
244  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
245 
246  sub->u.array.start_pos = sub->value_pos;
247  _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
248  sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
249 
250 #if RECURSIVE_MARSHAL_READ_TRACE
251  _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
252  sub,
253  sub->u.array.start_pos,
254  sub->array_len_offset,
255  array_reader_get_array_len (sub),
257  sub->type_pos)));
258 #endif
259 }
260 
261 static void
262 variant_reader_recurse (DBusTypeReader *sub,
263  DBusTypeReader *parent)
264 {
265  int sig_len;
266  int contained_alignment;
267 
268  base_reader_recurse (sub, parent);
269 
270  /* Variant is 1 byte sig length (without nul), signature with nul,
271  * padding to 8-boundary, then values
272  */
273 
274  sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
275 
276  sub->type_str = sub->value_str;
277  sub->type_pos = sub->value_pos + 1;
278 
279  sub->value_pos = sub->type_pos + sig_len + 1;
280 
282  sub->type_pos));
283 
284  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
285 
286 #if RECURSIVE_MARSHAL_READ_TRACE
287  _dbus_verbose (" type reader %p variant containing '%s'\n",
288  sub,
290  sub->type_pos, 0));
291 #endif
292 }
293 
294 static dbus_bool_t
295 array_reader_check_finished (const DBusTypeReader *reader)
296 {
297  int end_pos;
298 
299  /* return the array element type if elements remain, and
300  * TYPE_INVALID otherwise
301  */
302 
303  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
304 
305  _dbus_assert (reader->value_pos <= end_pos);
306  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
307 
308  return reader->value_pos == end_pos;
309 }
310 
311 static void
312 skip_one_complete_type (const DBusString *type_str,
313  int *type_pos)
314 {
316  type_pos);
317 }
318 
327 void
328 _dbus_type_signature_next (const char *type_str,
329  int *type_pos)
330 {
331  const unsigned char *p;
332  const unsigned char *start;
333 
334  _dbus_assert (type_str != NULL);
335  _dbus_assert (type_pos != NULL);
336 
337  start = type_str;
338  p = start + *type_pos;
339 
342 
343  while (*p == DBUS_TYPE_ARRAY)
344  ++p;
345 
348 
349  if (*p == DBUS_STRUCT_BEGIN_CHAR)
350  {
351  int depth;
352 
353  depth = 1;
354 
355  while (TRUE)
356  {
358 
359  ++p;
360 
362 
363  if (*p == DBUS_STRUCT_BEGIN_CHAR)
364  depth += 1;
365  else if (*p == DBUS_STRUCT_END_CHAR)
366  {
367  depth -= 1;
368  if (depth == 0)
369  {
370  ++p;
371  break;
372  }
373  }
374  }
375  }
376  else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
377  {
378  int depth;
379 
380  depth = 1;
381 
382  while (TRUE)
383  {
385 
386  ++p;
387 
389 
390  if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
391  depth += 1;
392  else if (*p == DBUS_DICT_ENTRY_END_CHAR)
393  {
394  depth -= 1;
395  if (depth == 0)
396  {
397  ++p;
398  break;
399  }
400  }
401  }
402  }
403  else
404  {
405  ++p;
406  }
407 
408  *type_pos = (int) (p - start);
409 }
410 
411 static int
412 find_len_of_complete_type (const DBusString *type_str,
413  int type_pos)
414 {
415  int end;
416 
417  end = type_pos;
418 
419  skip_one_complete_type (type_str, &end);
420 
421  return end - type_pos;
422 }
423 
424 static void
425 base_reader_next (DBusTypeReader *reader,
426  int current_type)
427 {
428  switch (current_type)
429  {
431  case DBUS_TYPE_STRUCT:
432  case DBUS_TYPE_VARIANT:
433  /* Scan forward over the entire container contents */
434  {
435  DBusTypeReader sub;
436 
437  if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT)
438  ;
439  else
440  {
441  /* Recurse into the struct or variant */
442  _dbus_type_reader_recurse (reader, &sub);
443 
444  /* Skip everything in this subreader */
445  while (_dbus_type_reader_next (&sub))
446  {
447  /* nothing */;
448  }
449  }
450  if (!reader->klass->types_only)
451  reader->value_pos = sub.value_pos;
452 
453  /* Now we are at the end of this container; for variants, the
454  * subreader's type_pos is totally inapplicable (it's in the
455  * value string) but we know that we increment by one past the
456  * DBUS_TYPE_VARIANT
457  */
458  if (current_type == DBUS_TYPE_VARIANT)
459  reader->type_pos += 1;
460  else
461  reader->type_pos = sub.type_pos;
462  }
463  break;
464 
465  case DBUS_TYPE_ARRAY:
466  {
467  if (!reader->klass->types_only)
470  reader->type_pos + 1),
471  reader->byte_order,
472  &reader->value_pos);
473 
474  skip_one_complete_type (reader->type_str, &reader->type_pos);
475  }
476  break;
477 
478  default:
479  if (!reader->klass->types_only)
481  current_type, reader->byte_order,
482  &reader->value_pos);
483 
484  reader->type_pos += 1;
485  break;
486  }
487 }
488 
489 static void
490 struct_reader_next (DBusTypeReader *reader,
491  int current_type)
492 {
493  int t;
494 
495  base_reader_next (reader, current_type);
496 
497  /* for STRUCT containers we return FALSE at the end of the struct,
498  * for INVALID we return FALSE at the end of the signature.
499  * In both cases we arrange for get_current_type() to return INVALID
500  * which is defined to happen iff we're at the end (no more next())
501  */
502  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
503  if (t == DBUS_STRUCT_END_CHAR)
504  {
505  reader->type_pos += 1;
506  reader->finished = TRUE;
507  }
508 }
509 
510 static void
511 dict_entry_reader_next (DBusTypeReader *reader,
512  int current_type)
513 {
514  int t;
515 
516  base_reader_next (reader, current_type);
517 
518  /* for STRUCT containers we return FALSE at the end of the struct,
519  * for INVALID we return FALSE at the end of the signature.
520  * In both cases we arrange for get_current_type() to return INVALID
521  * which is defined to happen iff we're at the end (no more next())
522  */
523  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
524  if (t == DBUS_DICT_ENTRY_END_CHAR)
525  {
526  reader->type_pos += 1;
527  reader->finished = TRUE;
528  }
529 }
530 
531 static void
532 array_types_only_reader_next (DBusTypeReader *reader,
533  int current_type)
534 {
535  /* We have one "element" to be iterated over
536  * in each array, which is its element type.
537  * So the finished flag indicates whether we've
538  * iterated over it yet or not.
539  */
540  reader->finished = TRUE;
541 }
542 
543 static void
544 array_reader_next (DBusTypeReader *reader,
545  int current_type)
546 {
547  /* Skip one array element */
548  int end_pos;
549 
550  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
551 
552 #if RECURSIVE_MARSHAL_READ_TRACE
553  _dbus_verbose (" reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
554  reader,
555  reader->u.array.start_pos,
556  end_pos, reader->value_pos,
557  _dbus_type_to_string (current_type));
558 #endif
559 
560  _dbus_assert (reader->value_pos < end_pos);
561  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
562 
563  switch (_dbus_first_type_in_signature (reader->type_str,
564  reader->type_pos))
565  {
567  case DBUS_TYPE_STRUCT:
568  case DBUS_TYPE_VARIANT:
569  {
570  DBusTypeReader sub;
571 
572  /* Recurse into the struct or variant */
573  _dbus_type_reader_recurse (reader, &sub);
574 
575  /* Skip everything in this element */
576  while (_dbus_type_reader_next (&sub))
577  {
578  /* nothing */;
579  }
580 
581  /* Now we are at the end of this element */
582  reader->value_pos = sub.value_pos;
583  }
584  break;
585 
586  case DBUS_TYPE_ARRAY:
587  {
590  reader->type_pos + 1),
591  reader->byte_order,
592  &reader->value_pos);
593  }
594  break;
595 
596  default:
597  {
599  current_type, reader->byte_order,
600  &reader->value_pos);
601  }
602  break;
603  }
604 
605 #if RECURSIVE_MARSHAL_READ_TRACE
606  _dbus_verbose (" reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
607  reader,
608  reader->u.array.start_pos,
609  end_pos, reader->value_pos,
610  _dbus_type_to_string (current_type));
611 #endif
612 
613  _dbus_assert (reader->value_pos <= end_pos);
614 
615  if (reader->value_pos == end_pos)
616  {
617  skip_one_complete_type (reader->type_str,
618  &reader->type_pos);
619  }
620 }
621 
622 static const DBusTypeReaderClass body_reader_class = {
623  "body", 0,
624  FALSE,
625  NULL, /* body is always toplevel, so doesn't get recursed into */
626  NULL,
627  base_reader_next
628 };
629 
630 static const DBusTypeReaderClass body_types_only_reader_class = {
631  "body types", 1,
632  TRUE,
633  NULL, /* body is always toplevel, so doesn't get recursed into */
634  NULL,
635  base_reader_next
636 };
637 
638 static const DBusTypeReaderClass struct_reader_class = {
639  "struct", 2,
640  FALSE,
641  struct_or_dict_entry_reader_recurse,
642  NULL,
643  struct_reader_next
644 };
645 
646 static const DBusTypeReaderClass struct_types_only_reader_class = {
647  "struct types", 3,
648  TRUE,
649  struct_or_dict_entry_types_only_reader_recurse,
650  NULL,
651  struct_reader_next
652 };
653 
654 static const DBusTypeReaderClass dict_entry_reader_class = {
655  "dict_entry", 4,
656  FALSE,
657  struct_or_dict_entry_reader_recurse,
658  NULL,
659  dict_entry_reader_next
660 };
661 
662 static const DBusTypeReaderClass dict_entry_types_only_reader_class = {
663  "dict_entry types", 5,
664  TRUE,
665  struct_or_dict_entry_types_only_reader_recurse,
666  NULL,
667  dict_entry_reader_next
668 };
669 
670 static const DBusTypeReaderClass array_reader_class = {
671  "array", 6,
672  FALSE,
673  array_reader_recurse,
674  array_reader_check_finished,
675  array_reader_next
676 };
677 
678 static const DBusTypeReaderClass array_types_only_reader_class = {
679  "array types", 7,
680  TRUE,
681  array_types_only_reader_recurse,
682  NULL,
683  array_types_only_reader_next
684 };
685 
686 static const DBusTypeReaderClass variant_reader_class = {
687  "variant", 8,
688  FALSE,
689  variant_reader_recurse,
690  NULL,
691  base_reader_next
692 };
693 
694 #ifndef DBUS_DISABLE_ASSERT
695 static const DBusTypeReaderClass * const
696 all_reader_classes[] = {
697  &body_reader_class,
698  &body_types_only_reader_class,
699  &struct_reader_class,
700  &struct_types_only_reader_class,
701  &dict_entry_reader_class,
702  &dict_entry_types_only_reader_class,
703  &array_reader_class,
704  &array_types_only_reader_class,
705  &variant_reader_class
706 };
707 #endif
708 
719 void
721  int byte_order,
722  const DBusString *type_str,
723  int type_pos,
724  const DBusString *value_str,
725  int value_pos)
726 {
727  reader->klass = &body_reader_class;
728 
729  reader_init (reader, byte_order, type_str, type_pos,
730  value_str, value_pos);
731 
732 #if RECURSIVE_MARSHAL_READ_TRACE
733  _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
734  reader, reader->type_pos, reader->value_pos,
735  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
736 #endif
737 }
738 
747 void
749  const DBusString *type_str,
750  int type_pos)
751 {
752  reader->klass = &body_types_only_reader_class;
753 
754  reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
755  type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
756 
757 #if RECURSIVE_MARSHAL_READ_TRACE
758  _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
759  reader, reader->type_pos,
760  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
761 #endif
762 }
763 
772 int
774 {
775  int t;
776 
777  if (reader->finished ||
778  (reader->klass->check_finished &&
779  (* reader->klass->check_finished) (reader)))
780  t = DBUS_TYPE_INVALID;
781  else
783  reader->type_pos);
784 
789 
790 #if 0
791  _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
792  reader, reader->type_pos,
794 #endif
795 
796  return t;
797 }
798 
807 int
809 {
810  int element_type;
811 
813 
814  element_type = _dbus_first_type_in_signature (reader->type_str,
815  reader->type_pos + 1);
816 
817  return element_type;
818 }
819 
824 int
826 {
827  return reader->value_pos;
828 }
829 
839 void
841  const unsigned char **value_location)
842 {
843  _dbus_assert (!reader->klass->types_only);
844 
845  *value_location = _dbus_string_get_const_data_len (reader->value_str,
846  reader->value_pos,
847  0);
848 }
849 
856 void
858  void *value)
859 {
860  int t;
861 
862  _dbus_assert (!reader->klass->types_only);
863 
865 
867  reader->value_pos,
868  t, value,
869  reader->byte_order,
870  NULL);
871 
872 
873 #if RECURSIVE_MARSHAL_READ_TRACE
874  _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
875  reader, reader->type_pos, reader->value_pos,
876  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
877 #endif
878 }
879 
886 int
888 {
889  _dbus_assert (!reader->klass->types_only);
890  _dbus_assert (reader->klass == &array_reader_class);
891 
892  return array_reader_get_array_len (reader);
893 }
894 
910 void
912  void *value,
913  int *n_elements)
914 {
915  int element_type;
916  int end_pos;
917  int remaining_len;
918  int alignment;
919  int total_len;
920 
921  _dbus_assert (!reader->klass->types_only);
922  _dbus_assert (reader->klass == &array_reader_class);
923 
924  element_type = _dbus_first_type_in_signature (reader->type_str,
925  reader->type_pos);
926 
927  _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
928  _dbus_assert (dbus_type_is_fixed (element_type));
929 
930  alignment = _dbus_type_get_alignment (element_type);
931 
932  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
933 
934  total_len = array_reader_get_array_len (reader);
935  end_pos = reader->u.array.start_pos + total_len;
936  remaining_len = end_pos - reader->value_pos;
937 
938 #if RECURSIVE_MARSHAL_READ_TRACE
939  _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",
940  end_pos, total_len, remaining_len, reader->value_pos);
941 #endif
942 
943  _dbus_assert (remaining_len <= total_len);
944 
945  if (remaining_len == 0)
946  *(const DBusBasicValue**) value = NULL;
947  else
948  *(const DBusBasicValue**) value =
950  reader->value_pos,
951  remaining_len);
952 
953  *n_elements = remaining_len / alignment;
954  _dbus_assert ((remaining_len % alignment) == 0);
955 
956 #if RECURSIVE_MARSHAL_READ_TRACE
957  _dbus_verbose (" type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
958  reader, reader->type_pos, reader->value_pos,
959  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
960 #endif
961 }
962 
975 void
977  DBusTypeReader *sub)
978 {
979  int t;
980 
981  t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos);
982 
983  switch (t)
984  {
985  case DBUS_TYPE_STRUCT:
986  if (reader->klass->types_only)
987  sub->klass = &struct_types_only_reader_class;
988  else
989  sub->klass = &struct_reader_class;
990  break;
992  if (reader->klass->types_only)
993  sub->klass = &dict_entry_types_only_reader_class;
994  else
995  sub->klass = &dict_entry_reader_class;
996  break;
997  case DBUS_TYPE_ARRAY:
998  if (reader->klass->types_only)
999  sub->klass = &array_types_only_reader_class;
1000  else
1001  sub->klass = &array_reader_class;
1002  break;
1003  case DBUS_TYPE_VARIANT:
1004  if (reader->klass->types_only)
1005  _dbus_assert_not_reached ("can't recurse into variant typecode");
1006  else
1007  sub->klass = &variant_reader_class;
1008  break;
1009  default:
1010  _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
1011 #ifndef DBUS_DISABLE_CHECKS
1012  if (t == DBUS_TYPE_INVALID)
1013  _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n");
1014 #endif /* DBUS_DISABLE_CHECKS */
1015 
1016  _dbus_assert_not_reached ("don't yet handle recursing into this type");
1017  }
1018 
1019  _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
1020 
1021  (* sub->klass->recurse) (sub, reader);
1022 
1023 #if RECURSIVE_MARSHAL_READ_TRACE
1024  _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
1025  sub, sub->type_pos, sub->value_pos,
1027 #endif
1028 }
1029 
1040 {
1041  int t;
1042 
1044 
1045 #if RECURSIVE_MARSHAL_READ_TRACE
1046  _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1047  reader, reader->type_pos, reader->value_pos,
1048  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1049  _dbus_type_to_string (t));
1050 #endif
1051 
1052  if (t == DBUS_TYPE_INVALID)
1053  return FALSE;
1054 
1055  (* reader->klass->next) (reader, t);
1056 
1057 #if RECURSIVE_MARSHAL_READ_TRACE
1058  _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1059  reader, reader->type_pos, reader->value_pos,
1060  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1062 #endif
1063 
1065 }
1066 
1080 {
1081  /* Not efficient but works for now. */
1082  DBusTypeReader copy;
1083 
1084  copy = *reader;
1085  return _dbus_type_reader_next (&copy);
1086 }
1087 
1109 void
1111  const DBusString **str_p,
1112  int *start_p,
1113  int *len_p)
1114 {
1115  *str_p = reader->type_str;
1116  *start_p = reader->type_pos;
1117  *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
1118 }
1119 
1120 typedef struct
1121 {
1123  int padding;
1125 
1126 static dbus_bool_t
1127 replacement_block_init (ReplacementBlock *block,
1128  DBusTypeReader *reader)
1129 {
1130  if (!_dbus_string_init (&block->replacement))
1131  return FALSE;
1132 
1133  /* % 8 is the padding to have the same align properties in
1134  * our replacement string as we do at the position being replaced
1135  */
1136  block->padding = reader->value_pos % 8;
1137 
1138  if (!_dbus_string_lengthen (&block->replacement, block->padding))
1139  goto oom;
1140 
1141  return TRUE;
1142 
1143  oom:
1144  _dbus_string_free (&block->replacement);
1145  return FALSE;
1146 }
1147 
1148 static dbus_bool_t
1149 replacement_block_replace (ReplacementBlock *block,
1150  DBusTypeReader *reader,
1151  const DBusTypeReader *realign_root)
1152 {
1153  DBusTypeWriter writer;
1154  DBusTypeReader realign_reader;
1155  DBusList *fixups;
1156  int orig_len;
1157 
1158  _dbus_assert (realign_root != NULL);
1159 
1160  orig_len = _dbus_string_get_length (&block->replacement);
1161 
1162  realign_reader = *realign_root;
1163 
1164 #if RECURSIVE_MARSHAL_WRITE_TRACE
1165  _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
1166  &writer, _dbus_string_get_length (&block->replacement));
1167 #endif
1169  realign_reader.byte_order,
1170  realign_reader.type_str,
1171  realign_reader.type_pos,
1172  &block->replacement,
1174 
1175  _dbus_assert (realign_reader.value_pos <= reader->value_pos);
1176 
1177 #if RECURSIVE_MARSHAL_WRITE_TRACE
1178  _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
1179  realign_reader.value_pos, &writer, reader->value_pos);
1180 #endif
1181  fixups = NULL;
1183  &realign_reader,
1184  reader,
1185  block->padding,
1186  _dbus_string_get_length (&block->replacement) - block->padding,
1187  &fixups))
1188  goto oom;
1189 
1190 #if RECURSIVE_MARSHAL_WRITE_TRACE
1191  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
1192  _dbus_string_get_length (&block->replacement) - block->padding);
1194  _dbus_string_get_length (&block->replacement) - block->padding);
1195  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
1196  reader->value_pos, reader->value_pos % 8,
1197  realign_reader.value_pos - reader->value_pos,
1198  realign_reader.value_pos);
1200  reader->value_pos,
1201  realign_reader.value_pos - reader->value_pos);
1202 #endif
1203 
1204  /* Move the replacement into position
1205  * (realign_reader should now be at the end of the block to be replaced)
1206  */
1207  if (!_dbus_string_replace_len (&block->replacement, block->padding,
1208  _dbus_string_get_length (&block->replacement) - block->padding,
1209  (DBusString*) reader->value_str,
1210  reader->value_pos,
1211  realign_reader.value_pos - reader->value_pos))
1212  goto oom;
1213 
1214  /* Process our fixups now that we can't have an OOM error */
1215  apply_and_free_fixups (&fixups, reader);
1216 
1217  return TRUE;
1218 
1219  oom:
1220  _dbus_string_set_length (&block->replacement, orig_len);
1221  free_fixups (&fixups);
1222  return FALSE;
1223 }
1224 
1225 static void
1226 replacement_block_free (ReplacementBlock *block)
1227 {
1228  _dbus_string_free (&block->replacement);
1229 }
1230 
1231 /* In the variable-length case, we have to fix alignment after we insert.
1232  * The strategy is as follows:
1233  *
1234  * - pad a new string to have the same alignment as the
1235  * start of the current basic value
1236  * - write the new basic value
1237  * - copy from the original reader to the new string,
1238  * which will fix the alignment of types following
1239  * the new value
1240  * - this copy has to start at realign_root,
1241  * but not really write anything until it
1242  * passes the value being set
1243  * - as an optimization, we can stop copying
1244  * when the source and dest values are both
1245  * on an 8-boundary, since we know all following
1246  * padding and alignment will be identical
1247  * - copy the new string back to the original
1248  * string, replacing the relevant part of the
1249  * original string
1250  * - now any arrays in the original string that
1251  * contained the replaced string may have the
1252  * wrong length; so we have to fix that
1253  */
1254 static dbus_bool_t
1255 reader_set_basic_variable_length (DBusTypeReader *reader,
1256  int current_type,
1257  const void *value,
1258  const DBusTypeReader *realign_root)
1259 {
1260  dbus_bool_t retval;
1261  ReplacementBlock block;
1262  DBusTypeWriter writer;
1263 
1264  _dbus_assert (realign_root != NULL);
1265 
1266  retval = FALSE;
1267 
1268  if (!replacement_block_init (&block, reader))
1269  return FALSE;
1270 
1271  /* Write the new basic value */
1272 #if RECURSIVE_MARSHAL_WRITE_TRACE
1273  _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
1274  &writer, _dbus_string_get_length (&block.replacement));
1275 #endif
1277  reader->byte_order,
1278  reader->type_str,
1279  reader->type_pos,
1280  &block.replacement,
1282 #if RECURSIVE_MARSHAL_WRITE_TRACE
1283  _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
1284 #endif
1285  if (!_dbus_type_writer_write_basic (&writer, current_type, value))
1286  goto out;
1287 
1288  if (!replacement_block_replace (&block,
1289  reader,
1290  realign_root))
1291  goto out;
1292 
1293  retval = TRUE;
1294 
1295  out:
1296  replacement_block_free (&block);
1297  return retval;
1298 }
1299 
1300 static void
1301 reader_set_basic_fixed_length (DBusTypeReader *reader,
1302  int current_type,
1303  const void *value)
1304 {
1306  reader->value_pos,
1307  current_type,
1308  value,
1309  reader->byte_order,
1310  NULL, NULL);
1311 }
1312 
1349  const void *value,
1350  const DBusTypeReader *realign_root)
1351 {
1352  int current_type;
1353 
1354  _dbus_assert (!reader->klass->types_only);
1355  _dbus_assert (reader->value_str == realign_root->value_str);
1356  _dbus_assert (reader->value_pos >= realign_root->value_pos);
1357 
1358  current_type = _dbus_type_reader_get_current_type (reader);
1359 
1360 #if RECURSIVE_MARSHAL_WRITE_TRACE
1361  _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",
1362  reader, reader->type_pos, reader->value_pos,
1363  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1364  realign_root,
1365  realign_root ? realign_root->value_pos : -1,
1366  _dbus_type_to_string (current_type));
1367  _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
1368  _dbus_string_get_length (realign_root->value_str) -
1369  realign_root->value_pos);
1370 #endif
1371 
1372  _dbus_assert (dbus_type_is_basic (current_type));
1373 
1374  if (dbus_type_is_fixed (current_type))
1375  {
1376  reader_set_basic_fixed_length (reader, current_type, value);
1377  return TRUE;
1378  }
1379  else
1380  {
1381  _dbus_assert (realign_root != NULL);
1382  return reader_set_basic_variable_length (reader, current_type,
1383  value, realign_root);
1384  }
1385 }
1386 
1406  const DBusTypeReader *realign_root)
1407 {
1408  dbus_bool_t retval;
1409  ReplacementBlock block;
1410 
1411  _dbus_assert (realign_root != NULL);
1412  _dbus_assert (reader->klass == &array_reader_class);
1413 
1414  retval = FALSE;
1415 
1416  if (!replacement_block_init (&block, reader))
1417  return FALSE;
1418 
1419  if (!replacement_block_replace (&block,
1420  reader,
1421  realign_root))
1422  goto out;
1423 
1424  retval = TRUE;
1425 
1426  out:
1427  replacement_block_free (&block);
1428  return retval;
1429 }
1430 
1441  const DBusTypeReader *rhs)
1442 {
1443  _dbus_assert (lhs->value_str == rhs->value_str);
1444 
1445  return lhs->value_pos > rhs->value_pos;
1446 }
1447 
1448 /*
1449  *
1450  *
1451  * DBusTypeWriter
1452  *
1453  *
1454  *
1455  */
1456 
1477 void
1479  int byte_order,
1480  DBusString *type_str,
1481  int type_pos,
1482  DBusString *value_str,
1483  int value_pos)
1484 {
1485  writer->byte_order = byte_order;
1486  writer->type_str = type_str;
1487  writer->type_pos = type_pos;
1488  writer->value_str = value_str;
1489  writer->value_pos = value_pos;
1491  writer->type_pos_is_expectation = FALSE;
1492  writer->enabled = TRUE;
1493 
1494 #if RECURSIVE_MARSHAL_WRITE_TRACE
1495  _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1496  writer->type_str ?
1497  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1498  "unknown");
1499 #endif
1500 }
1501 
1512 void
1514  int byte_order,
1515  DBusString *value_str,
1516  int value_pos)
1517 {
1518  _dbus_type_writer_init (writer, byte_order,
1519  NULL, 0, value_str, value_pos);
1520 }
1521 
1530 void
1532  DBusString *type_str,
1533  int type_pos)
1534 {
1535  if (writer->type_str == NULL) /* keeps us from using this as setter */
1536  {
1537  writer->type_str = type_str;
1538  writer->type_pos = type_pos;
1539  }
1540 }
1541 
1547 void
1549 {
1550  writer->type_str = NULL;
1551  writer->type_pos = -1;
1552 }
1553 
1568 void
1570  int byte_order,
1571  const DBusString *type_str,
1572  int type_pos,
1573  DBusString *value_str,
1574  int value_pos)
1575 {
1576  _dbus_type_writer_init (writer, byte_order,
1577  (DBusString*)type_str, type_pos,
1578  value_str, value_pos);
1579 
1580  writer->type_pos_is_expectation = TRUE;
1581 }
1582 
1583 static dbus_bool_t
1584 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1585  int type,
1586  const void *value)
1587 {
1588  if (writer->enabled)
1589  return _dbus_marshal_write_basic (writer->value_str,
1590  writer->value_pos,
1591  type,
1592  value,
1593  writer->byte_order,
1594  &writer->value_pos);
1595  else
1596  return TRUE;
1597 }
1598 
1599 /* If our parent is an array, things are a little bit complicated.
1600  *
1601  * The parent must have a complete element type, such as
1602  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1603  * unclosed parens, or an "a" with no following type.
1604  *
1605  * To recurse, the only allowed operation is to recurse into the
1606  * first type in the element type. So for "i" you can't recurse, for
1607  * "ai" you can recurse into the array, for "(ii)" you can recurse
1608  * into the struct.
1609  *
1610  * If you recurse into the array for "ai", then you must specify
1611  * "i" for the element type of the array you recurse into.
1612  *
1613  * While inside an array at any level, we need to avoid writing to
1614  * type_str, since the type only appears once for the whole array,
1615  * it does not appear for each array element.
1616  *
1617  * While inside an array type_pos points to the expected next
1618  * typecode, rather than the next place we could write a typecode.
1619  */
1620 static void
1621 writer_recurse_init_and_check (DBusTypeWriter *writer,
1622  int container_type,
1623  DBusTypeWriter *sub)
1624 {
1626  writer->byte_order,
1627  writer->type_str,
1628  writer->type_pos,
1629  writer->value_str,
1630  writer->value_pos);
1631 
1632  sub->container_type = container_type;
1633 
1634  if (writer->type_pos_is_expectation ||
1637  else
1639 
1640  sub->enabled = writer->enabled;
1641 
1642 #ifndef DBUS_DISABLE_CHECKS
1643  if (writer->type_pos_is_expectation && writer->type_str)
1644  {
1645  int expected;
1646 
1647  expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos);
1648 
1649  if (expected != sub->container_type)
1650  {
1651  if (expected != DBUS_TYPE_INVALID)
1652  _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"
1653  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1655  _dbus_type_to_string (expected),
1656  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1657  else
1658  _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n"
1659  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1661  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1662 
1663  _dbus_assert_not_reached ("bad array element or variant content written");
1664  }
1665  }
1666 #endif /* DBUS_DISABLE_CHECKS */
1667 
1668 #if RECURSIVE_MARSHAL_WRITE_TRACE
1669  _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
1670  writer,
1672  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1673  writer->type_str ?
1674  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1675  "unknown",
1676  writer->enabled);
1677  _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
1678  sub,
1680  sub->type_pos, sub->value_pos,
1682  sub->enabled);
1683 #endif
1684 }
1685 
1686 static dbus_bool_t
1687 write_or_verify_typecode (DBusTypeWriter *writer,
1688  int typecode)
1689 {
1690  /* A subwriter inside an array or variant will have type_pos
1691  * pointing to the expected typecode; a writer not inside an array
1692  * or variant has type_pos pointing to the next place to insert a
1693  * typecode.
1694  */
1695 #if RECURSIVE_MARSHAL_WRITE_TRACE
1696  _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
1697  writer, writer->type_pos,
1698  writer->type_str ?
1699  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1700  "unknown",
1701  writer->enabled);
1702 #endif
1703 
1704  if (writer->type_str == NULL)
1705  return TRUE;
1706 
1707  if (writer->type_pos_is_expectation)
1708  {
1709 #ifndef DBUS_DISABLE_CHECKS
1710  {
1711  int expected;
1712 
1713  expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1714 
1715  if (expected != typecode)
1716  {
1717  if (expected != DBUS_TYPE_INVALID)
1718  _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"
1719  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1720  _dbus_type_to_string (expected), _dbus_type_to_string (typecode),
1721  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1722  else
1723  _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"
1724  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1725  _dbus_type_to_string (typecode),
1726  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1727  _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1728  }
1729  }
1730 #endif /* DBUS_DISABLE_CHECKS */
1731 
1732  /* if immediately inside an array we'd always be appending an element,
1733  * so the expected type doesn't change; if inside a struct or something
1734  * below an array, we need to move through said struct or something.
1735  */
1736  if (writer->container_type != DBUS_TYPE_ARRAY)
1737  writer->type_pos += 1;
1738  }
1739  else
1740  {
1741  if (!_dbus_string_insert_byte (writer->type_str,
1742  writer->type_pos,
1743  typecode))
1744  return FALSE;
1745 
1746  writer->type_pos += 1;
1747  }
1748 
1749 #if RECURSIVE_MARSHAL_WRITE_TRACE
1750  _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1751  writer, writer->type_pos,
1752  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1753 #endif
1754 
1755  return TRUE;
1756 }
1757 
1758 static dbus_bool_t
1759 writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer,
1760  int begin_char,
1761  const DBusString *contained_type,
1762  int contained_type_start,
1763  int contained_type_len,
1764  DBusTypeWriter *sub)
1765 {
1766  /* FIXME right now contained_type is ignored; we could probably
1767  * almost trivially fix the code so if it's present we
1768  * write it out and then set type_pos_is_expectation
1769  */
1770 
1771  /* Ensure that we'll be able to add alignment padding and the typecode */
1772  if (writer->enabled)
1773  {
1774  if (!_dbus_string_alloc_space (sub->value_str, 8))
1775  return FALSE;
1776  }
1777 
1778  if (!write_or_verify_typecode (sub, begin_char))
1779  _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1780 
1781  if (writer->enabled)
1782  {
1784  sub->value_pos,
1785  _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1786  '\0'))
1787  _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1788  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1789  }
1790 
1791  return TRUE;
1792 }
1793 
1794 
1795 static dbus_bool_t
1796 writer_recurse_array (DBusTypeWriter *writer,
1797  const DBusString *contained_type,
1798  int contained_type_start,
1799  int contained_type_len,
1800  DBusTypeWriter *sub,
1801  dbus_bool_t is_array_append)
1802 {
1803  dbus_uint32_t value = 0;
1804  int alignment;
1805  int aligned;
1806 
1807 #ifndef DBUS_DISABLE_CHECKS
1808  if (writer->container_type == DBUS_TYPE_ARRAY &&
1809  writer->type_str)
1810  {
1811  if (!_dbus_string_equal_substring (contained_type,
1812  contained_type_start,
1813  contained_type_len,
1814  writer->type_str,
1815  writer->u.array.element_type_pos + 1))
1816  {
1817  _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1818  _dbus_string_get_const_data_len (contained_type,
1819  contained_type_start,
1820  contained_type_len));
1821  _dbus_assert_not_reached ("incompatible type for child array");
1822  }
1823  }
1824 #endif /* DBUS_DISABLE_CHECKS */
1825 
1826  if (writer->enabled && !is_array_append)
1827  {
1828  /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1829  * before array values
1830  */
1831  if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1832  return FALSE;
1833  }
1834 
1835  if (writer->type_str != NULL)
1836  {
1837  sub->type_pos += 1; /* move to point to the element type, since type_pos
1838  * should be the expected type for further writes
1839  */
1840  sub->u.array.element_type_pos = sub->type_pos;
1841  }
1842 
1843  if (!writer->type_pos_is_expectation)
1844  {
1845  /* sub is a toplevel/outermost array so we need to write the type data */
1846 
1847  /* alloc space for array typecode, element signature */
1848  if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1849  return FALSE;
1850 
1851  if (!_dbus_string_insert_byte (writer->type_str,
1852  writer->type_pos,
1853  DBUS_TYPE_ARRAY))
1854  _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1855 
1856  if (!_dbus_string_copy_len (contained_type,
1857  contained_type_start, contained_type_len,
1858  sub->type_str,
1859  sub->u.array.element_type_pos))
1860  _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1861  }
1862 
1863  if (writer->type_str != NULL)
1864  {
1865  /* If the parent is an array, we hold type_pos pointing at the array element type;
1866  * otherwise advance it to reflect the array value we just recursed into
1867  */
1868  if (writer->container_type != DBUS_TYPE_ARRAY)
1869  writer->type_pos += 1 + contained_type_len;
1870  else
1871  _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1872  }
1873 
1874  if (writer->enabled)
1875  {
1876  /* Write (or jump over, if is_array_append) the length */
1877  sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1878 
1879  if (is_array_append)
1880  {
1881  sub->value_pos += 4;
1882  }
1883  else
1884  {
1885  if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1886  &value))
1887  _dbus_assert_not_reached ("should not have failed to insert array len");
1888  }
1889 
1890  _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1891 
1892  /* Write alignment padding for array elements
1893  * Note that we write the padding *even for empty arrays*
1894  * to avoid wonky special cases
1895  */
1896  alignment = element_type_get_alignment (contained_type, contained_type_start);
1897 
1898  aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1899  if (aligned != sub->value_pos)
1900  {
1901  if (!is_array_append)
1902  {
1904  sub->value_pos,
1905  aligned - sub->value_pos,
1906  '\0'))
1907  _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1908  }
1909 
1910  sub->value_pos = aligned;
1911  }
1912 
1913  sub->u.array.start_pos = sub->value_pos;
1914 
1915  if (is_array_append)
1916  {
1917  dbus_uint32_t len;
1918 
1919  _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==
1920  (unsigned) sub->u.array.len_pos);
1921  len = _dbus_unpack_uint32 (sub->byte_order,
1923  sub->u.array.len_pos,
1924  4));
1925 
1926  sub->value_pos += len;
1927  }
1928  }
1929  else
1930  {
1931  /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
1932  sub->u.array.len_pos = -1;
1933  sub->u.array.start_pos = sub->value_pos;
1934  }
1935 
1936  _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1937  _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
1938 
1939 #if RECURSIVE_MARSHAL_WRITE_TRACE
1940  _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
1941  sub->type_str ?
1943  "unknown",
1944  sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
1945 #endif
1946 
1947  return TRUE;
1948 }
1949 
1950 /* Variant value will normally have:
1951  * 1 byte signature length not including nul
1952  * signature typecodes (nul terminated)
1953  * padding to alignment of contained type
1954  * body according to signature
1955  *
1956  * The signature string can only have a single type
1957  * in it but that type may be complex/recursive.
1958  *
1959  * So a typical variant type with the integer 3 will have these
1960  * octets:
1961  * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3
1962  *
1963  * The main world of hurt for writing out a variant is that the type
1964  * string is the same string as the value string. Which means
1965  * inserting to the type string will move the value_pos; and it means
1966  * that inserting to the type string could break type alignment.
1967  */
1968 static dbus_bool_t
1969 writer_recurse_variant (DBusTypeWriter *writer,
1970  const DBusString *contained_type,
1971  int contained_type_start,
1972  int contained_type_len,
1973  DBusTypeWriter *sub)
1974 {
1975  int contained_alignment;
1976 
1977  if (writer->enabled)
1978  {
1979  /* Allocate space for the worst case, which is 1 byte sig
1980  * length, nul byte at end of sig, and 7 bytes padding to
1981  * 8-boundary.
1982  */
1983  if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1984  return FALSE;
1985  }
1986 
1987  /* write VARIANT typecode to the parent's type string */
1988  if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1989  return FALSE;
1990 
1991  /* If not enabled, mark that we have no type_str anymore ... */
1992 
1993  if (!writer->enabled)
1994  {
1995  sub->type_str = NULL;
1996  sub->type_pos = -1;
1997 
1998  return TRUE;
1999  }
2000 
2001  /* If we're enabled then continue ... */
2002 
2004  sub->value_pos,
2005  contained_type_len))
2006  _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
2007 
2008  sub->value_pos += 1;
2009 
2010  /* Here we switch over to the expected type sig we're about to write */
2011  sub->type_str = sub->value_str;
2012  sub->type_pos = sub->value_pos;
2013 
2014  if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
2015  sub->value_str, sub->value_pos))
2016  _dbus_assert_not_reached ("should not have failed to insert variant type sig");
2017 
2018  sub->value_pos += contained_type_len;
2019 
2021  sub->value_pos,
2023  _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
2024 
2025  sub->value_pos += 1;
2026 
2027  contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));
2028 
2030  sub->value_pos,
2031  _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,
2032  '\0'))
2033  _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
2034  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
2035 
2036  return TRUE;
2037 }
2038 
2039 static dbus_bool_t
2040 _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer,
2041  int container_type,
2042  const DBusString *contained_type,
2043  int contained_type_start,
2044  int contained_type_len,
2045  DBusTypeWriter *sub,
2046  dbus_bool_t is_array_append)
2047 {
2048  writer_recurse_init_and_check (writer, container_type, sub);
2049 
2050  switch (container_type)
2051  {
2052  case DBUS_TYPE_STRUCT:
2053  return writer_recurse_struct_or_dict_entry (writer,
2055  contained_type,
2056  contained_type_start, contained_type_len,
2057  sub);
2058  break;
2059  case DBUS_TYPE_DICT_ENTRY:
2060  return writer_recurse_struct_or_dict_entry (writer,
2062  contained_type,
2063  contained_type_start, contained_type_len,
2064  sub);
2065  break;
2066  case DBUS_TYPE_ARRAY:
2067  return writer_recurse_array (writer,
2068  contained_type, contained_type_start, contained_type_len,
2069  sub, is_array_append);
2070  break;
2071  case DBUS_TYPE_VARIANT:
2072  return writer_recurse_variant (writer,
2073  contained_type, contained_type_start, contained_type_len,
2074  sub);
2075  break;
2076  default:
2077  _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
2078  return FALSE;
2079  break;
2080  }
2081 }
2082 
2095  int container_type,
2096  const DBusString *contained_type,
2097  int contained_type_start,
2098  DBusTypeWriter *sub)
2099 {
2100  int contained_type_len;
2101 
2102  if (contained_type)
2103  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2104  else
2105  contained_type_len = 0;
2106 
2107  return _dbus_type_writer_recurse_contained_len (writer, container_type,
2108  contained_type,
2109  contained_type_start,
2110  contained_type_len,
2111  sub,
2112  FALSE);
2113 }
2114 
2129  const DBusString *contained_type,
2130  int contained_type_start,
2131  DBusTypeWriter *sub)
2132 {
2133  int contained_type_len;
2134 
2135  if (contained_type)
2136  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2137  else
2138  contained_type_len = 0;
2139 
2140  return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
2141  contained_type,
2142  contained_type_start,
2143  contained_type_len,
2144  sub,
2145  TRUE);
2146 }
2147 
2148 static int
2149 writer_get_array_len (DBusTypeWriter *writer)
2150 {
2152  return writer->value_pos - writer->u.array.start_pos;
2153 }
2154 
2165  DBusTypeWriter *sub)
2166 {
2167  /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
2170 
2171 #if RECURSIVE_MARSHAL_WRITE_TRACE
2172  _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2173  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2175  _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2176  sub, sub->type_pos, sub->value_pos,
2179 #endif
2180 
2181  if (sub->container_type == DBUS_TYPE_STRUCT)
2182  {
2183  if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
2184  return FALSE;
2185  }
2186  else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
2187  {
2188  if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
2189  return FALSE;
2190  }
2191  else if (sub->container_type == DBUS_TYPE_ARRAY)
2192  {
2193  if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
2194  {
2195  dbus_uint32_t len;
2196 
2197  /* Set the array length */
2198  len = writer_get_array_len (sub);
2200  sub->u.array.len_pos,
2201  len,
2202  sub->byte_order);
2203 #if RECURSIVE_MARSHAL_WRITE_TRACE
2204  _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
2205  len, sub->u.array.len_pos);
2206 #endif
2207  }
2208 #if RECURSIVE_MARSHAL_WRITE_TRACE
2209  else
2210  {
2211  _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n");
2212  }
2213 #endif
2214  }
2215 
2216  /* Now get type_pos right for the parent writer. Here are the cases:
2217  *
2218  * Cases !writer->type_pos_is_expectation:
2219  * (in these cases we want to update to the new insertion point)
2220  *
2221  * - if we recursed into a STRUCT then we didn't know in advance
2222  * what the types in the struct would be; so we have to fill in
2223  * that information now.
2224  * writer->type_pos = sub->type_pos
2225  *
2226  * - if we recursed into anything else, we knew the full array
2227  * type, or knew the single typecode marking VARIANT, so
2228  * writer->type_pos is already correct.
2229  * writer->type_pos should remain as-is
2230  *
2231  * - note that the parent is never an ARRAY or VARIANT, if it were
2232  * then type_pos_is_expectation would be TRUE. The parent
2233  * is thus known to be a toplevel or STRUCT.
2234  *
2235  * Cases where writer->type_pos_is_expectation:
2236  * (in these cases we want to update to next expected type to write)
2237  *
2238  * - we recursed from STRUCT into STRUCT and we didn't increment
2239  * type_pos in the parent just to stay consistent with the
2240  * !writer->type_pos_is_expectation case (though we could
2241  * special-case this in recurse_struct instead if we wanted)
2242  * writer->type_pos = sub->type_pos
2243  *
2244  * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
2245  * for parent should have been incremented already
2246  * writer->type_pos should remain as-is
2247  *
2248  * - we recursed from ARRAY into a sub-element, so type_pos in the
2249  * parent is the element type and should remain the element type
2250  * for the benefit of the next child element
2251  * writer->type_pos should remain as-is
2252  *
2253  * - we recursed from VARIANT into its value, so type_pos in the
2254  * parent makes no difference since there's only one value
2255  * and we just finished writing it and won't use type_pos again
2256  * writer->type_pos should remain as-is
2257  *
2258  *
2259  * For all these, DICT_ENTRY is the same as STRUCT
2260  */
2261  if (writer->type_str != NULL)
2262  {
2263  if ((sub->container_type == DBUS_TYPE_STRUCT ||
2265  (writer->container_type == DBUS_TYPE_STRUCT ||
2266  writer->container_type == DBUS_TYPE_DICT_ENTRY ||
2267  writer->container_type == DBUS_TYPE_INVALID))
2268  {
2269  /* Advance the parent to the next struct field */
2270  writer->type_pos = sub->type_pos;
2271  }
2272  }
2273 
2274  writer->value_pos = sub->value_pos;
2275 
2276 #if RECURSIVE_MARSHAL_WRITE_TRACE
2277  _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
2278  writer, writer->type_pos, writer->value_pos,
2279  writer->type_str ?
2280  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
2281  "unknown");
2282 #endif
2283 
2284  return TRUE;
2285 }
2286 
2297  int type,
2298  const void *value)
2299 {
2300  dbus_bool_t retval;
2301 
2302  /* First ensure that our type realloc will succeed */
2303  if (!writer->type_pos_is_expectation && writer->type_str != NULL)
2304  {
2305  if (!_dbus_string_alloc_space (writer->type_str, 1))
2306  return FALSE;
2307  }
2308 
2309  retval = FALSE;
2310 
2311  if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
2312  goto out;
2313 
2314  if (!write_or_verify_typecode (writer, type))
2315  _dbus_assert_not_reached ("failed to write typecode after prealloc");
2316 
2317  retval = TRUE;
2318 
2319  out:
2320 #if RECURSIVE_MARSHAL_WRITE_TRACE
2321  _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
2322  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2323  writer->enabled);
2324 #endif
2325 
2326  return retval;
2327 }
2328 
2345  int element_type,
2346  const void *value,
2347  int n_elements)
2348 {
2350  _dbus_assert (dbus_type_is_fixed (element_type));
2352  _dbus_assert (n_elements >= 0);
2353 
2354 #if RECURSIVE_MARSHAL_WRITE_TRACE
2355  _dbus_verbose (" type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",
2356  writer, writer->type_pos, writer->value_pos, n_elements);
2357 #endif
2358 
2359  if (!write_or_verify_typecode (writer, element_type))
2360  _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
2361 
2362  if (writer->enabled)
2363  {
2365  writer->value_pos,
2366  element_type,
2367  value,
2368  n_elements,
2369  writer->byte_order,
2370  &writer->value_pos))
2371  return FALSE;
2372  }
2373 
2374 #if RECURSIVE_MARSHAL_WRITE_TRACE
2375  _dbus_verbose (" type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",
2376  writer, writer->type_pos, writer->value_pos, n_elements);
2377 #endif
2378 
2379  return TRUE;
2380 }
2381 
2382 static void
2383 enable_if_after (DBusTypeWriter *writer,
2384  DBusTypeReader *reader,
2385  const DBusTypeReader *start_after)
2386 {
2387  if (start_after)
2388  {
2389  if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))
2390  {
2392 #if RECURSIVE_MARSHAL_WRITE_TRACE
2393  _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",
2394  writer, writer->value_pos, reader->value_pos, start_after->value_pos);
2395 #endif
2396  }
2397 
2398  _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||
2399  (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));
2400  }
2401 }
2402 
2403 static dbus_bool_t
2404 append_fixup (DBusList **fixups,
2405  const DBusArrayLenFixup *fixup)
2406 {
2407  DBusArrayLenFixup *f;
2408 
2409  f = dbus_new (DBusArrayLenFixup, 1);
2410  if (f == NULL)
2411  return FALSE;
2412 
2413  *f = *fixup;
2414 
2415  if (!_dbus_list_append (fixups, f))
2416  {
2417  dbus_free (f);
2418  return FALSE;
2419  }
2420 
2422  _dbus_assert (f->new_len == fixup->new_len);
2423 
2424  return TRUE;
2425 }
2426 
2427 /* This loop is trivial if you ignore all the start_after nonsense,
2428  * so if you're trying to figure it out, start by ignoring that
2429  */
2430 static dbus_bool_t
2431 writer_write_reader_helper (DBusTypeWriter *writer,
2432  DBusTypeReader *reader,
2433  const DBusTypeReader *start_after,
2434  int start_after_new_pos,
2435  int start_after_new_len,
2436  DBusList **fixups,
2437  dbus_bool_t inside_start_after)
2438 {
2439  int current_type;
2440 
2441  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
2442  {
2443  if (dbus_type_is_container (current_type))
2444  {
2445  DBusTypeReader subreader;
2446  DBusTypeWriter subwriter;
2447  const DBusString *sig_str;
2448  int sig_start;
2449  int sig_len;
2450  dbus_bool_t enabled_at_recurse;
2451  dbus_bool_t past_start_after;
2452  int reader_array_len_pos;
2453  int reader_array_start_pos;
2454  dbus_bool_t this_is_start_after;
2455 
2456  /* type_pos is checked since e.g. in a struct the struct
2457  * and its first field have the same value_pos.
2458  * type_str will differ in reader/start_after for variants
2459  * where type_str is inside the value_str
2460  */
2461  if (!inside_start_after && start_after &&
2462  reader->value_pos == start_after->value_pos &&
2463  reader->type_str == start_after->type_str &&
2464  reader->type_pos == start_after->type_pos)
2465  this_is_start_after = TRUE;
2466  else
2467  this_is_start_after = FALSE;
2468 
2469  _dbus_type_reader_recurse (reader, &subreader);
2470 
2471  if (current_type == DBUS_TYPE_ARRAY)
2472  {
2473  reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);
2474  reader_array_start_pos = subreader.u.array.start_pos;
2475  }
2476  else
2477  {
2478  /* quiet gcc */
2479  reader_array_len_pos = -1;
2480  reader_array_start_pos = -1;
2481  }
2482 
2483  _dbus_type_reader_get_signature (&subreader, &sig_str,
2484  &sig_start, &sig_len);
2485 
2486 #if RECURSIVE_MARSHAL_WRITE_TRACE
2487  _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",
2488  _dbus_type_to_string (current_type),
2489  reader->value_pos,
2490  subreader.value_pos,
2491  writer->value_pos,
2492  start_after ? start_after->value_pos : -1,
2494  inside_start_after, this_is_start_after);
2495 #endif
2496 
2497  if (!inside_start_after && !this_is_start_after)
2498  enable_if_after (writer, &subreader, start_after);
2499  enabled_at_recurse = writer->enabled;
2500  if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
2501  sig_str, sig_start, sig_len,
2502  &subwriter, FALSE))
2503  goto oom;
2504 
2505 #if RECURSIVE_MARSHAL_WRITE_TRACE
2506  _dbus_verbose ("recursed into subwriter at %d write target len %d\n",
2507  subwriter.value_pos,
2508  _dbus_string_get_length (subwriter.value_str));
2509 #endif
2510 
2511  if (!writer_write_reader_helper (&subwriter, &subreader, start_after,
2512  start_after_new_pos, start_after_new_len,
2513  fixups,
2514  inside_start_after ||
2515  this_is_start_after))
2516  goto oom;
2517 
2518 #if RECURSIVE_MARSHAL_WRITE_TRACE
2519  _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d write target len %d\n",
2520  _dbus_type_to_string (current_type),
2521  subreader.value_pos,
2522  writer->value_pos,
2523  subwriter.value_pos,
2525 #endif
2526 
2527  if (!inside_start_after && !this_is_start_after)
2528  enable_if_after (writer, &subreader, start_after);
2529  past_start_after = writer->enabled;
2530  if (!_dbus_type_writer_unrecurse (writer, &subwriter))
2531  goto oom;
2532 
2533  /* If we weren't enabled when we recursed, we didn't
2534  * write an array len; if we passed start_after
2535  * somewhere inside the array, then we need to generate
2536  * a fixup.
2537  */
2538  if (start_after != NULL &&
2539  !enabled_at_recurse && past_start_after &&
2540  current_type == DBUS_TYPE_ARRAY &&
2541  fixups != NULL)
2542  {
2543  DBusArrayLenFixup fixup;
2544  int bytes_written_after_start_after;
2545  int bytes_before_start_after;
2546  int old_len;
2547 
2548  /* this subwriter access is moderately unkosher since we
2549  * already unrecursed, but it works as long as unrecurse
2550  * doesn't break us on purpose
2551  */
2552  bytes_written_after_start_after = writer_get_array_len (&subwriter);
2553 
2554  bytes_before_start_after =
2555  start_after->value_pos - reader_array_start_pos;
2556 
2557  fixup.len_pos_in_reader = reader_array_len_pos;
2558  fixup.new_len =
2559  bytes_before_start_after +
2560  start_after_new_len +
2561  bytes_written_after_start_after;
2562 
2563  _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) ==
2564  (unsigned) fixup.len_pos_in_reader);
2565 
2566  old_len = _dbus_unpack_uint32 (reader->byte_order,
2568  fixup.len_pos_in_reader, 4));
2569 
2570  if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))
2571  goto oom;
2572 
2573 #if RECURSIVE_MARSHAL_WRITE_TRACE
2574  _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",
2575  fixup.len_pos_in_reader,
2576  fixup.new_len,
2577  reader_array_start_pos,
2578  start_after->value_pos,
2579  bytes_before_start_after,
2580  start_after_new_len,
2581  bytes_written_after_start_after);
2582 #endif
2583  }
2584  }
2585  else
2586  {
2587  DBusBasicValue val;
2588 
2589  _dbus_assert (dbus_type_is_basic (current_type));
2590 
2591 #if RECURSIVE_MARSHAL_WRITE_TRACE
2592  _dbus_verbose ("Reading basic value %s at %d\n",
2593  _dbus_type_to_string (current_type),
2594  reader->value_pos);
2595 #endif
2596 
2597  _dbus_type_reader_read_basic (reader, &val);
2598 
2599 #if RECURSIVE_MARSHAL_WRITE_TRACE
2600  _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",
2601  _dbus_type_to_string (current_type),
2602  writer->value_pos,
2604  inside_start_after);
2605 #endif
2606  if (!inside_start_after)
2607  enable_if_after (writer, reader, start_after);
2608  if (!_dbus_type_writer_write_basic (writer, current_type, &val))
2609  goto oom;
2610 #if RECURSIVE_MARSHAL_WRITE_TRACE
2611  _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",
2612  _dbus_type_to_string (current_type),
2613  writer->value_pos,
2615 #endif
2616  }
2617 
2618  _dbus_type_reader_next (reader);
2619  }
2620 
2621  return TRUE;
2622 
2623  oom:
2624  if (fixups)
2625  apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */
2626 
2627  return FALSE;
2628 }
2629 
2663  DBusTypeReader *reader,
2664  const DBusTypeReader *start_after,
2665  int start_after_new_pos,
2666  int start_after_new_len,
2667  DBusList **fixups)
2668 {
2669  DBusTypeWriter orig;
2670  int orig_type_len;
2671  int orig_value_len;
2672  int new_bytes;
2673  int orig_enabled;
2674 
2675  orig = *writer;
2676  orig_type_len = _dbus_string_get_length (writer->type_str);
2677  orig_value_len = _dbus_string_get_length (writer->value_str);
2678  orig_enabled = writer->enabled;
2679 
2680  if (start_after)
2682 
2683  if (!writer_write_reader_helper (writer, reader, start_after,
2684  start_after_new_pos,
2685  start_after_new_len,
2686  fixups, FALSE))
2687  goto oom;
2688 
2689  _dbus_type_writer_set_enabled (writer, orig_enabled);
2690  return TRUE;
2691 
2692  oom:
2693  if (!writer->type_pos_is_expectation)
2694  {
2695  new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
2696  _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
2697  }
2698  new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
2699  _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
2700 
2701  *writer = orig;
2702 
2703  return FALSE;
2704 }
2705 
2717  DBusTypeReader *reader)
2718 {
2719  return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
2720 }
2721 
2731 void
2733  dbus_bool_t enabled)
2734 {
2735  writer->enabled = enabled != FALSE;
2736 }
2737  /* end of DBusMarshal group */
2739 
2740 /* tests in dbus-marshal-recursive-util.c */