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