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