D-Bus  1.10.32
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_data_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 = 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_data_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  const DBusTypeReaderClass *klass;
993  int t;
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\n");
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 == all_reader_classes[klass->id]);
1034 
1035  (* klass->recurse) (sub, reader);
1036  sub->klass = klass;
1037 
1038 #if RECURSIVE_MARSHAL_READ_TRACE
1039  _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
1040  sub, sub->type_pos, sub->value_pos,
1041  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
1042 #endif
1043 }
1044 
1055 {
1056  int t;
1057 
1059 
1060 #if RECURSIVE_MARSHAL_READ_TRACE
1061  _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1062  reader, reader->type_pos, reader->value_pos,
1063  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1064  _dbus_type_to_string (t));
1065 #endif
1066 
1067  if (t == DBUS_TYPE_INVALID)
1068  return FALSE;
1069 
1070  (* reader->klass->next) (reader, t);
1071 
1072 #if RECURSIVE_MARSHAL_READ_TRACE
1073  _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
1074  reader, reader->type_pos, reader->value_pos,
1075  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1077 #endif
1078 
1080 }
1081 
1095 {
1096  /* Not efficient but works for now. */
1097  DBusTypeReader copy;
1098 
1099  copy = *reader;
1100  return _dbus_type_reader_next (&copy);
1101 }
1102 
1124 void
1126  const DBusString **str_p,
1127  int *start_p,
1128  int *len_p)
1129 {
1130  *str_p = reader->type_str;
1131  *start_p = reader->type_pos;
1132  *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
1133 }
1134 
1135 typedef struct
1136 {
1138  int padding;
1140 
1141 static dbus_bool_t
1142 replacement_block_init (ReplacementBlock *block,
1143  DBusTypeReader *reader)
1144 {
1145  if (!_dbus_string_init (&block->replacement))
1146  return FALSE;
1147 
1148  /* % 8 is the padding to have the same align properties in
1149  * our replacement string as we do at the position being replaced
1150  */
1151  block->padding = reader->value_pos % 8;
1152 
1153  if (!_dbus_string_lengthen (&block->replacement, block->padding))
1154  goto oom;
1155 
1156  return TRUE;
1157 
1158  oom:
1159  _dbus_string_free (&block->replacement);
1160  return FALSE;
1161 }
1162 
1163 static dbus_bool_t
1164 replacement_block_replace (ReplacementBlock *block,
1165  DBusTypeReader *reader,
1166  const DBusTypeReader *realign_root)
1167 {
1168  DBusTypeWriter writer;
1169  DBusTypeReader realign_reader;
1170  DBusList *fixups;
1171  int orig_len;
1172 
1173  _dbus_assert (realign_root != NULL);
1174 
1175  orig_len = _dbus_string_get_length (&block->replacement);
1176 
1177  realign_reader = *realign_root;
1178 
1179 #if RECURSIVE_MARSHAL_WRITE_TRACE
1180  _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
1181  &writer, _dbus_string_get_length (&block->replacement));
1182 #endif
1184  realign_reader.byte_order,
1185  realign_reader.type_str,
1186  realign_reader.type_pos,
1187  &block->replacement,
1188  _dbus_string_get_length (&block->replacement));
1189 
1190  _dbus_assert (realign_reader.value_pos <= reader->value_pos);
1191 
1192 #if RECURSIVE_MARSHAL_WRITE_TRACE
1193  _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
1194  realign_reader.value_pos, &writer, reader->value_pos);
1195 #endif
1196  fixups = NULL;
1197  if (!_dbus_type_writer_write_reader_partial (&writer,
1198  &realign_reader,
1199  reader,
1200  block->padding,
1201  _dbus_string_get_length (&block->replacement) - block->padding,
1202  &fixups))
1203  goto oom;
1204 
1205 #if RECURSIVE_MARSHAL_WRITE_TRACE
1206  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
1207  _dbus_string_get_length (&block->replacement) - block->padding);
1209  _dbus_string_get_length (&block->replacement) - block->padding);
1210  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
1211  reader->value_pos, reader->value_pos % 8,
1212  realign_reader.value_pos - reader->value_pos,
1213  realign_reader.value_pos);
1215  reader->value_pos,
1216  realign_reader.value_pos - reader->value_pos);
1217 #endif
1218 
1219  /* Move the replacement into position
1220  * (realign_reader should now be at the end of the block to be replaced)
1221  */
1222  if (!_dbus_string_replace_len (&block->replacement, block->padding,
1223  _dbus_string_get_length (&block->replacement) - block->padding,
1224  (DBusString*) reader->value_str,
1225  reader->value_pos,
1226  realign_reader.value_pos - reader->value_pos))
1227  goto oom;
1228 
1229  /* Process our fixups now that we can't have an OOM error */
1230  apply_and_free_fixups (&fixups, reader);
1231 
1232  return TRUE;
1233 
1234  oom:
1235  _dbus_string_set_length (&block->replacement, orig_len);
1236  free_fixups (&fixups);
1237  return FALSE;
1238 }
1239 
1240 static void
1241 replacement_block_free (ReplacementBlock *block)
1242 {
1243  _dbus_string_free (&block->replacement);
1244 }
1245 
1246 /* In the variable-length case, we have to fix alignment after we insert.
1247  * The strategy is as follows:
1248  *
1249  * - pad a new string to have the same alignment as the
1250  * start of the current basic value
1251  * - write the new basic value
1252  * - copy from the original reader to the new string,
1253  * which will fix the alignment of types following
1254  * the new value
1255  * - this copy has to start at realign_root,
1256  * but not really write anything until it
1257  * passes the value being set
1258  * - as an optimization, we can stop copying
1259  * when the source and dest values are both
1260  * on an 8-boundary, since we know all following
1261  * padding and alignment will be identical
1262  * - copy the new string back to the original
1263  * string, replacing the relevant part of the
1264  * original string
1265  * - now any arrays in the original string that
1266  * contained the replaced string may have the
1267  * wrong length; so we have to fix that
1268  */
1269 static dbus_bool_t
1270 reader_set_basic_variable_length (DBusTypeReader *reader,
1271  int current_type,
1272  const void *value,
1273  const DBusTypeReader *realign_root)
1274 {
1275  dbus_bool_t retval;
1276  ReplacementBlock block;
1277  DBusTypeWriter writer;
1278 
1279  _dbus_assert (realign_root != NULL);
1280 
1281  retval = FALSE;
1282 
1283  if (!replacement_block_init (&block, reader))
1284  return FALSE;
1285 
1286  /* Write the new basic value */
1287 #if RECURSIVE_MARSHAL_WRITE_TRACE
1288  _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
1289  &writer, _dbus_string_get_length (&block.replacement));
1290 #endif
1292  reader->byte_order,
1293  reader->type_str,
1294  reader->type_pos,
1295  &block.replacement,
1296  _dbus_string_get_length (&block.replacement));
1297 #if RECURSIVE_MARSHAL_WRITE_TRACE
1298  _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
1299 #endif
1300  if (!_dbus_type_writer_write_basic (&writer, current_type, value))
1301  goto out;
1302 
1303  if (!replacement_block_replace (&block,
1304  reader,
1305  realign_root))
1306  goto out;
1307 
1308  retval = TRUE;
1309 
1310  out:
1311  replacement_block_free (&block);
1312  return retval;
1313 }
1314 
1315 static void
1316 reader_set_basic_fixed_length (DBusTypeReader *reader,
1317  int current_type,
1318  const void *value)
1319 {
1321  reader->value_pos,
1322  current_type,
1323  value,
1324  reader->byte_order,
1325  NULL, NULL);
1326 }
1327 
1364  const void *value,
1365  const DBusTypeReader *realign_root)
1366 {
1367  int current_type;
1368 
1369  _dbus_assert (!reader->klass->types_only);
1370  _dbus_assert (reader->value_str == realign_root->value_str);
1371  _dbus_assert (reader->value_pos >= realign_root->value_pos);
1372 
1373  current_type = _dbus_type_reader_get_current_type (reader);
1374 
1375 #if RECURSIVE_MARSHAL_WRITE_TRACE
1376  _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",
1377  reader, reader->type_pos, reader->value_pos,
1378  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
1379  realign_root,
1380  realign_root ? realign_root->value_pos : -1,
1381  _dbus_type_to_string (current_type));
1382  _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
1383  _dbus_string_get_length (realign_root->value_str) -
1384  realign_root->value_pos);
1385 #endif
1386 
1387  _dbus_assert (dbus_type_is_basic (current_type));
1388 
1389  if (dbus_type_is_fixed (current_type))
1390  {
1391  reader_set_basic_fixed_length (reader, current_type, value);
1392  return TRUE;
1393  }
1394  else
1395  {
1396  _dbus_assert (realign_root != NULL);
1397  return reader_set_basic_variable_length (reader, current_type,
1398  value, realign_root);
1399  }
1400 }
1401 
1421  const DBusTypeReader *realign_root)
1422 {
1423  dbus_bool_t retval;
1424  ReplacementBlock block;
1425 
1426  _dbus_assert (realign_root != NULL);
1427  _dbus_assert (reader->klass == &array_reader_class);
1428 
1429  retval = FALSE;
1430 
1431  if (!replacement_block_init (&block, reader))
1432  return FALSE;
1433 
1434  if (!replacement_block_replace (&block,
1435  reader,
1436  realign_root))
1437  goto out;
1438 
1439  retval = TRUE;
1440 
1441  out:
1442  replacement_block_free (&block);
1443  return retval;
1444 }
1445 
1446 /*
1447  * Compares two readers, which must be iterating over the same value data.
1448  * Returns #TRUE if the first parameter is further along than the second parameter.
1449  *
1450  * @param lhs left-hand-side (first) parameter
1451  * @param rhs left-hand-side (first) parameter
1452  * @returns whether lhs is greater than rhs
1453  */
1454 static dbus_bool_t
1455 _dbus_type_reader_greater_than (const DBusTypeReader *lhs,
1456  const DBusTypeReader *rhs)
1457 {
1458  _dbus_assert (lhs->value_str == rhs->value_str);
1459 
1460  return lhs->value_pos > rhs->value_pos;
1461 }
1462 
1463 /*
1464  *
1465  *
1466  * DBusTypeWriter
1467  *
1468  *
1469  *
1470  */
1471 
1492 void
1494  int byte_order,
1495  DBusString *type_str,
1496  int type_pos,
1497  DBusString *value_str,
1498  int value_pos)
1499 {
1500  writer->byte_order = byte_order;
1501  writer->type_str = type_str;
1502  writer->type_pos = type_pos;
1503  writer->value_str = value_str;
1504  writer->value_pos = value_pos;
1506  writer->type_pos_is_expectation = FALSE;
1507  writer->enabled = TRUE;
1508 
1509 #if RECURSIVE_MARSHAL_WRITE_TRACE
1510  _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1511  writer->type_str ?
1512  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1513  "unknown");
1514 #endif
1515 }
1516 
1527 void
1529  int byte_order,
1530  DBusString *value_str,
1531  int value_pos)
1532 {
1533  _dbus_type_writer_init (writer, byte_order,
1534  NULL, 0, value_str, value_pos);
1535 }
1536 
1545 void
1547  DBusString *type_str,
1548  int type_pos)
1549 {
1550  if (writer->type_str == NULL) /* keeps us from using this as setter */
1551  {
1552  writer->type_str = type_str;
1553  writer->type_pos = type_pos;
1554  }
1555 }
1556 
1562 void
1564 {
1565  writer->type_str = NULL;
1566  writer->type_pos = -1;
1567 }
1568 
1583 void
1585  int byte_order,
1586  const DBusString *type_str,
1587  int type_pos,
1588  DBusString *value_str,
1589  int value_pos)
1590 {
1591  _dbus_type_writer_init (writer, byte_order,
1592  (DBusString*)type_str, type_pos,
1593  value_str, value_pos);
1594 
1595  writer->type_pos_is_expectation = TRUE;
1596 }
1597 
1598 static dbus_bool_t
1599 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1600  int type,
1601  const void *value)
1602 {
1603  if (writer->enabled)
1604  return _dbus_marshal_write_basic (writer->value_str,
1605  writer->value_pos,
1606  type,
1607  value,
1608  writer->byte_order,
1609  &writer->value_pos);
1610  else
1611  return TRUE;
1612 }
1613 
1614 /* If our parent is an array, things are a little bit complicated.
1615  *
1616  * The parent must have a complete element type, such as
1617  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1618  * unclosed parens, or an "a" with no following type.
1619  *
1620  * To recurse, the only allowed operation is to recurse into the
1621  * first type in the element type. So for "i" you can't recurse, for
1622  * "ai" you can recurse into the array, for "(ii)" you can recurse
1623  * into the struct.
1624  *
1625  * If you recurse into the array for "ai", then you must specify
1626  * "i" for the element type of the array you recurse into.
1627  *
1628  * While inside an array at any level, we need to avoid writing to
1629  * type_str, since the type only appears once for the whole array,
1630  * it does not appear for each array element.
1631  *
1632  * While inside an array type_pos points to the expected next
1633  * typecode, rather than the next place we could write a typecode.
1634  */
1635 static void
1636 writer_recurse_init_and_check (DBusTypeWriter *writer,
1637  int container_type,
1638  DBusTypeWriter *sub)
1639 {
1641  writer->byte_order,
1642  writer->type_str,
1643  writer->type_pos,
1644  writer->value_str,
1645  writer->value_pos);
1646 
1647  sub->container_type = container_type;
1648 
1649  if (writer->type_pos_is_expectation ||
1652  else
1654 
1655  sub->enabled = writer->enabled;
1656 
1657 #ifndef DBUS_DISABLE_CHECKS
1658  if (writer->type_pos_is_expectation && writer->type_str)
1659  {
1660  int expected;
1661 
1662  expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos);
1663 
1664  if (expected != sub->container_type)
1665  {
1666  if (expected != DBUS_TYPE_INVALID)
1667  _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"
1668  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1670  _dbus_type_to_string (expected),
1671  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1672  else
1673  _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n"
1674  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1676  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1677 
1678  _dbus_assert_not_reached ("bad array element or variant content written");
1679  }
1680  }
1681 #endif /* DBUS_DISABLE_CHECKS */
1682 
1683 #if RECURSIVE_MARSHAL_WRITE_TRACE
1684  _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
1685  writer,
1687  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1688  writer->type_str ?
1689  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1690  "unknown",
1691  writer->enabled);
1692  _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
1693  sub,
1695  sub->type_pos, sub->value_pos,
1697  sub->enabled);
1698 #endif
1699 }
1700 
1701 static dbus_bool_t
1702 write_or_verify_typecode (DBusTypeWriter *writer,
1703  int typecode)
1704 {
1705  /* A subwriter inside an array or variant will have type_pos
1706  * pointing to the expected typecode; a writer not inside an array
1707  * or variant has type_pos pointing to the next place to insert a
1708  * typecode.
1709  */
1710 #if RECURSIVE_MARSHAL_WRITE_TRACE
1711  _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
1712  writer, writer->type_pos,
1713  writer->type_str ?
1714  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1715  "unknown",
1716  writer->enabled);
1717 #endif
1718 
1719  if (writer->type_str == NULL)
1720  return TRUE;
1721 
1722  if (writer->type_pos_is_expectation)
1723  {
1724 #ifndef DBUS_DISABLE_CHECKS
1725  {
1726  int expected;
1727 
1728  expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1729 
1730  if (expected != typecode)
1731  {
1732  if (expected != DBUS_TYPE_INVALID)
1733  _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"
1734  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1735  _dbus_type_to_string (expected), _dbus_type_to_string (typecode),
1736  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1737  else
1738  _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"
1739  "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
1740  _dbus_type_to_string (typecode),
1741  _dbus_string_get_const_data (writer->type_str), writer->type_pos);
1742  _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1743  }
1744  }
1745 #endif /* DBUS_DISABLE_CHECKS */
1746 
1747  /* if immediately inside an array we'd always be appending an element,
1748  * so the expected type doesn't change; if inside a struct or something
1749  * below an array, we need to move through said struct or something.
1750  */
1751  if (writer->container_type != DBUS_TYPE_ARRAY)
1752  writer->type_pos += 1;
1753  }
1754  else
1755  {
1756  if (!_dbus_string_insert_byte (writer->type_str,
1757  writer->type_pos,
1758  typecode))
1759  return FALSE;
1760 
1761  writer->type_pos += 1;
1762  }
1763 
1764 #if RECURSIVE_MARSHAL_WRITE_TRACE
1765  _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1766  writer, writer->type_pos,
1767  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1768 #endif
1769 
1770  return TRUE;
1771 }
1772 
1773 static dbus_bool_t
1774 writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer,
1775  int begin_char,
1776  const DBusString *contained_type,
1777  int contained_type_start,
1778  int contained_type_len,
1779  DBusTypeWriter *sub)
1780 {
1781  /* FIXME right now contained_type is ignored; we could probably
1782  * almost trivially fix the code so if it's present we
1783  * write it out and then set type_pos_is_expectation
1784  */
1785 
1786  /* Ensure that we'll be able to add alignment padding and the typecode */
1787  if (writer->enabled)
1788  {
1789  if (!_dbus_string_alloc_space (sub->value_str, 8))
1790  return FALSE;
1791  }
1792 
1793  if (!write_or_verify_typecode (sub, begin_char))
1794  _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1795 
1796  if (writer->enabled)
1797  {
1799  sub->value_pos,
1800  _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1801  '\0'))
1802  _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1803  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1804  }
1805 
1806  return TRUE;
1807 }
1808 
1809 
1810 static dbus_bool_t
1811 writer_recurse_array (DBusTypeWriter *writer,
1812  const DBusString *contained_type,
1813  int contained_type_start,
1814  int contained_type_len,
1815  DBusTypeWriter *sub,
1816  dbus_bool_t is_array_append)
1817 {
1818  dbus_uint32_t value = 0;
1819  int alignment;
1820  int aligned;
1821 
1822 #ifndef DBUS_DISABLE_CHECKS
1823  if (writer->container_type == DBUS_TYPE_ARRAY &&
1824  writer->type_str)
1825  {
1826  if (!_dbus_string_equal_substring (contained_type,
1827  contained_type_start,
1828  contained_type_len,
1829  writer->type_str,
1830  writer->u.array.element_type_pos + 1))
1831  {
1832  _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1833  _dbus_string_get_const_data_len (contained_type,
1834  contained_type_start,
1835  contained_type_len));
1836  _dbus_assert_not_reached ("incompatible type for child array");
1837  }
1838  }
1839 #endif /* DBUS_DISABLE_CHECKS */
1840 
1841  if (writer->enabled && !is_array_append)
1842  {
1843  /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1844  * before array values
1845  */
1846  if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1847  return FALSE;
1848  }
1849 
1850  if (writer->type_str != NULL)
1851  {
1852  sub->type_pos += 1; /* move to point to the element type, since type_pos
1853  * should be the expected type for further writes
1854  */
1855  sub->u.array.element_type_pos = sub->type_pos;
1856  }
1857 
1858  if (!writer->type_pos_is_expectation)
1859  {
1860  /* sub is a toplevel/outermost array so we need to write the type data */
1861 
1862  /* alloc space for array typecode, element signature */
1863  if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1864  return FALSE;
1865 
1866  if (!_dbus_string_insert_byte (writer->type_str,
1867  writer->type_pos,
1868  DBUS_TYPE_ARRAY))
1869  _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1870 
1871  if (!_dbus_string_copy_len (contained_type,
1872  contained_type_start, contained_type_len,
1873  sub->type_str,
1874  sub->u.array.element_type_pos))
1875  _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1876  }
1877 
1878  if (writer->type_str != NULL)
1879  {
1880  /* If the parent is an array, we hold type_pos pointing at the array element type;
1881  * otherwise advance it to reflect the array value we just recursed into
1882  */
1883  if (writer->container_type != DBUS_TYPE_ARRAY)
1884  writer->type_pos += 1 + contained_type_len;
1885  else
1886  _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1887  }
1888 
1889  if (writer->enabled)
1890  {
1891  /* Write (or jump over, if is_array_append) the length */
1892  sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1893 
1894  if (is_array_append)
1895  {
1896  sub->value_pos += 4;
1897  }
1898  else
1899  {
1900  if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1901  &value))
1902  _dbus_assert_not_reached ("should not have failed to insert array len");
1903  }
1904 
1905  _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1906 
1907  /* Write alignment padding for array elements
1908  * Note that we write the padding *even for empty arrays*
1909  * to avoid wonky special cases
1910  */
1911  alignment = element_type_get_alignment (contained_type, contained_type_start);
1912 
1913  aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1914  if (aligned != sub->value_pos)
1915  {
1916  if (!is_array_append)
1917  {
1919  sub->value_pos,
1920  aligned - sub->value_pos,
1921  '\0'))
1922  _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1923  }
1924 
1925  sub->value_pos = aligned;
1926  }
1927 
1928  sub->u.array.start_pos = sub->value_pos;
1929 
1930  if (is_array_append)
1931  {
1932  dbus_uint32_t len;
1933 
1934  _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==
1935  (unsigned) sub->u.array.len_pos);
1936  len = _dbus_unpack_uint32 (sub->byte_order,
1937  _dbus_string_get_const_data_len (sub->value_str,
1938  sub->u.array.len_pos,
1939  4));
1940 
1941  sub->value_pos += len;
1942  }
1943  }
1944  else
1945  {
1946  /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
1947  sub->u.array.len_pos = -1;
1948  sub->u.array.start_pos = sub->value_pos;
1949  }
1950 
1951  _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1952  _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
1953 
1954 #if RECURSIVE_MARSHAL_WRITE_TRACE
1955  _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
1956  sub->type_str ?
1957  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
1958  "unknown",
1959  sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
1960 #endif
1961 
1962  return TRUE;
1963 }
1964 
1965 /* Variant value will normally have:
1966  * 1 byte signature length not including nul
1967  * signature typecodes (nul terminated)
1968  * padding to alignment of contained type
1969  * body according to signature
1970  *
1971  * The signature string can only have a single type
1972  * in it but that type may be complex/recursive.
1973  *
1974  * So a typical variant type with the integer 3 will have these
1975  * octets:
1976  * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3
1977  *
1978  * The main world of hurt for writing out a variant is that the type
1979  * string is the same string as the value string. Which means
1980  * inserting to the type string will move the value_pos; and it means
1981  * that inserting to the type string could break type alignment.
1982  */
1983 static dbus_bool_t
1984 writer_recurse_variant (DBusTypeWriter *writer,
1985  const DBusString *contained_type,
1986  int contained_type_start,
1987  int contained_type_len,
1988  DBusTypeWriter *sub)
1989 {
1990  int contained_alignment;
1991 
1992  if (writer->enabled)
1993  {
1994  /* Allocate space for the worst case, which is 1 byte sig
1995  * length, nul byte at end of sig, and 7 bytes padding to
1996  * 8-boundary.
1997  */
1998  if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1999  return FALSE;
2000  }
2001 
2002  /* write VARIANT typecode to the parent's type string */
2003  if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
2004  return FALSE;
2005 
2006  /* If not enabled, mark that we have no type_str anymore ... */
2007 
2008  if (!writer->enabled)
2009  {
2010  sub->type_str = NULL;
2011  sub->type_pos = -1;
2012 
2013  return TRUE;
2014  }
2015 
2016  /* If we're enabled then continue ... */
2017 
2019  sub->value_pos,
2020  contained_type_len))
2021  _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
2022 
2023  sub->value_pos += 1;
2024 
2025  /* Here we switch over to the expected type sig we're about to write */
2026  sub->type_str = sub->value_str;
2027  sub->type_pos = sub->value_pos;
2028 
2029  if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
2030  sub->value_str, sub->value_pos))
2031  _dbus_assert_not_reached ("should not have failed to insert variant type sig");
2032 
2033  sub->value_pos += contained_type_len;
2034 
2036  sub->value_pos,
2038  _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
2039 
2040  sub->value_pos += 1;
2041 
2042  contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));
2043 
2045  sub->value_pos,
2046  _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,
2047  '\0'))
2048  _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
2049  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
2050 
2051  return TRUE;
2052 }
2053 
2054 static dbus_bool_t
2055 _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer,
2056  int container_type,
2057  const DBusString *contained_type,
2058  int contained_type_start,
2059  int contained_type_len,
2060  DBusTypeWriter *sub,
2061  dbus_bool_t is_array_append)
2062 {
2063  writer_recurse_init_and_check (writer, container_type, sub);
2064 
2065  switch (container_type)
2066  {
2067  case DBUS_TYPE_STRUCT:
2068  return writer_recurse_struct_or_dict_entry (writer,
2070  contained_type,
2071  contained_type_start, contained_type_len,
2072  sub);
2073  break;
2074  case DBUS_TYPE_DICT_ENTRY:
2075  return writer_recurse_struct_or_dict_entry (writer,
2077  contained_type,
2078  contained_type_start, contained_type_len,
2079  sub);
2080  break;
2081  case DBUS_TYPE_ARRAY:
2082  return writer_recurse_array (writer,
2083  contained_type, contained_type_start, contained_type_len,
2084  sub, is_array_append);
2085  break;
2086  case DBUS_TYPE_VARIANT:
2087  return writer_recurse_variant (writer,
2088  contained_type, contained_type_start, contained_type_len,
2089  sub);
2090  break;
2091  default:
2092  _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
2093  return FALSE;
2094  break;
2095  }
2096 }
2097 
2110  int container_type,
2111  const DBusString *contained_type,
2112  int contained_type_start,
2113  DBusTypeWriter *sub)
2114 {
2115  int contained_type_len;
2116 
2117  if (contained_type)
2118  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2119  else
2120  contained_type_len = 0;
2121 
2122  return _dbus_type_writer_recurse_contained_len (writer, container_type,
2123  contained_type,
2124  contained_type_start,
2125  contained_type_len,
2126  sub,
2127  FALSE);
2128 }
2129 
2144  const DBusString *contained_type,
2145  int contained_type_start,
2146  DBusTypeWriter *sub)
2147 {
2148  int contained_type_len;
2149 
2150  if (contained_type)
2151  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
2152  else
2153  contained_type_len = 0;
2154 
2155  return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
2156  contained_type,
2157  contained_type_start,
2158  contained_type_len,
2159  sub,
2160  TRUE);
2161 }
2162 
2163 static int
2164 writer_get_array_len (DBusTypeWriter *writer)
2165 {
2167  return writer->value_pos - writer->u.array.start_pos;
2168 }
2169 
2180  DBusTypeWriter *sub)
2181 {
2182  /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
2185 
2186 #if RECURSIVE_MARSHAL_WRITE_TRACE
2187  _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2188  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
2190  _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
2191  sub, sub->type_pos, sub->value_pos,
2194 #endif
2195 
2196  if (sub->container_type == DBUS_TYPE_STRUCT)
2197  {
2198  if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
2199  return FALSE;
2200  }
2201  else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
2202  {
2203  if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
2204  return FALSE;
2205  }
2206  else if (sub->container_type == DBUS_TYPE_ARRAY)
2207  {
2208  if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
2209  {
2210  dbus_uint32_t len;
2211 
2212  /* Set the array length */
2213  len = writer_get_array_len (sub);
2215  sub->u.array.len_pos,
2216  len,
2217  sub->byte_order);
2218 #if RECURSIVE_MARSHAL_WRITE_TRACE
2219  _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
2220  len, sub->u.array.len_pos);
2221 #endif
2222  }
2223 #if RECURSIVE_MARSHAL_WRITE_TRACE
2224  else
2225  {
2226  _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n");
2227  }
2228 #endif
2229  }
2230 
2231  /* Now get type_pos right for the parent writer. Here are the cases:
2232  *
2233  * Cases !writer->type_pos_is_expectation:
2234  * (in these cases we want to update to the new insertion point)
2235  *
2236  * - if we recursed into a STRUCT then we didn't know in advance
2237  * what the types in the struct would be; so we have to fill in
2238  * that information now.
2239  * writer->type_pos = sub->type_pos
2240  *
2241  * - if we recursed into anything else, we knew the full array
2242  * type, or knew the single typecode marking VARIANT, so
2243  * writer->type_pos is already correct.
2244  * writer->type_pos should remain as-is
2245  *
2246  * - note that the parent is never an ARRAY or VARIANT, if it were
2247  * then type_pos_is_expectation would be TRUE. The parent
2248  * is thus known to be a toplevel or STRUCT.
2249  *
2250  * Cases where writer->type_pos_is_expectation:
2251  * (in these cases we want to update to next expected type to write)
2252  *
2253  * - we recursed from STRUCT into STRUCT and we didn't increment
2254  * type_pos in the parent just to stay consistent with the
2255  * !writer->type_pos_is_expectation case (though we could
2256  * special-case this in recurse_struct instead if we wanted)
2257  * writer->type_pos = sub->type_pos
2258  *
2259  * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
2260  * for parent should have been incremented already
2261  * writer->type_pos should remain as-is
2262  *
2263  * - we recursed from ARRAY into a sub-element, so type_pos in the
2264  * parent is the element type and should remain the element type
2265  * for the benefit of the next child element
2266  * writer->type_pos should remain as-is
2267  *
2268  * - we recursed from VARIANT into its value, so type_pos in the
2269  * parent makes no difference since there's only one value
2270  * and we just finished writing it and won't use type_pos again
2271  * writer->type_pos should remain as-is
2272  *
2273  *
2274  * For all these, DICT_ENTRY is the same as STRUCT
2275  */
2276  if (writer->type_str != NULL)
2277  {
2278  if ((sub->container_type == DBUS_TYPE_STRUCT ||
2280  (writer->container_type == DBUS_TYPE_STRUCT ||
2281  writer->container_type == DBUS_TYPE_DICT_ENTRY ||
2282  writer->container_type == DBUS_TYPE_INVALID))
2283  {
2284  /* Advance the parent to the next struct field */
2285  writer->type_pos = sub->type_pos;
2286  }
2287  }
2288 
2289  writer->value_pos = sub->value_pos;
2290 
2291 #if RECURSIVE_MARSHAL_WRITE_TRACE
2224  NULL)
1997  */  /* Advance the parent to the next struct field */ 2285  writer->