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