D-Bus
1.6.8
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-marshal-recursive.c Marshalling routines for recursive types 00003 * 00004 * Copyright (C) 2004, 2005 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-marshal-recursive.h" 00026 #include "dbus-marshal-basic.h" 00027 #include "dbus-signature.h" 00028 #include "dbus-internals.h" 00029 00035 static dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs, 00036 const DBusTypeReader *rhs); 00037 00038 static void _dbus_type_writer_set_enabled (DBusTypeWriter *writer, 00039 dbus_bool_t enabled); 00040 static dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, 00041 DBusTypeReader *reader, 00042 const DBusTypeReader *start_after, 00043 int start_after_new_pos, 00044 int start_after_new_len, 00045 DBusList **fixups); 00046 00048 #define RECURSIVE_MARSHAL_READ_TRACE 0 00049 00051 #define RECURSIVE_MARSHAL_WRITE_TRACE 0 00052 00053 static void 00054 free_fixups (DBusList **fixups) 00055 { 00056 DBusList *link; 00057 00058 link = _dbus_list_get_first_link (fixups); 00059 while (link != NULL) 00060 { 00061 DBusList *next; 00062 00063 next = _dbus_list_get_next_link (fixups, link); 00064 00065 dbus_free (link->data); 00066 _dbus_list_free_link (link); 00067 00068 link = next; 00069 } 00070 00071 *fixups = NULL; 00072 } 00073 00074 static void 00075 apply_and_free_fixups (DBusList **fixups, 00076 DBusTypeReader *reader) 00077 { 00078 DBusList *link; 00079 00080 #if RECURSIVE_MARSHAL_WRITE_TRACE 00081 if (*fixups) 00082 _dbus_verbose (" %d FIXUPS to apply\n", 00083 _dbus_list_get_length (fixups)); 00084 #endif 00085 00086 link = _dbus_list_get_first_link (fixups); 00087 while (link != NULL) 00088 { 00089 DBusList *next; 00090 00091 next = _dbus_list_get_next_link (fixups, link); 00092 00093 if (reader) 00094 { 00095 DBusArrayLenFixup *f; 00096 00097 f = link->data; 00098 00099 #if RECURSIVE_MARSHAL_WRITE_TRACE 00100 _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n", 00101 reader, f->len_pos_in_reader, f->new_len, 00102 _dbus_marshal_read_uint32 (reader->value_str, 00103 f->len_pos_in_reader, 00104 reader->byte_order, NULL)); 00105 #endif 00106 00107 _dbus_marshal_set_uint32 ((DBusString*) reader->value_str, 00108 f->len_pos_in_reader, 00109 f->new_len, 00110 reader->byte_order); 00111 } 00112 00113 dbus_free (link->data); 00114 _dbus_list_free_link (link); 00115 00116 link = next; 00117 } 00118 00119 *fixups = NULL; 00120 } 00121 00125 struct DBusTypeReaderClass 00126 { 00127 const char *name; 00128 int id; 00129 dbus_bool_t types_only; 00130 void (* recurse) (DBusTypeReader *sub, 00131 DBusTypeReader *parent); 00132 dbus_bool_t (* check_finished) (const DBusTypeReader *reader); 00133 void (* next) (DBusTypeReader *reader, 00134 int current_type); 00135 }; 00136 00137 static int 00138 element_type_get_alignment (const DBusString *str, 00139 int pos) 00140 { 00141 return _dbus_type_get_alignment (_dbus_first_type_in_signature (str, pos)); 00142 } 00143 00144 static void 00145 reader_init (DBusTypeReader *reader, 00146 int byte_order, 00147 const DBusString *type_str, 00148 int type_pos, 00149 const DBusString *value_str, 00150 int value_pos) 00151 { 00152 reader->byte_order = byte_order; 00153 reader->finished = FALSE; 00154 reader->type_str = type_str; 00155 reader->type_pos = type_pos; 00156 reader->value_str = value_str; 00157 reader->value_pos = value_pos; 00158 } 00159 00160 static void 00161 base_reader_recurse (DBusTypeReader *sub, 00162 DBusTypeReader *parent) 00163 { 00164 /* point subreader at the same place as parent */ 00165 reader_init (sub, 00166 parent->byte_order, 00167 parent->type_str, 00168 parent->type_pos, 00169 parent->value_str, 00170 parent->value_pos); 00171 } 00172 00173 static void 00174 struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub, 00175 DBusTypeReader *parent) 00176 { 00177 base_reader_recurse (sub, parent); 00178 00179 _dbus_assert (_dbus_string_get_byte (sub->type_str, 00180 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR || 00181 _dbus_string_get_byte (sub->type_str, 00182 sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR); 00183 00184 sub->type_pos += 1; 00185 } 00186 00187 static void 00188 struct_or_dict_entry_reader_recurse (DBusTypeReader *sub, 00189 DBusTypeReader *parent) 00190 { 00191 struct_or_dict_entry_types_only_reader_recurse (sub, parent); 00192 00193 /* struct and dict entry have 8 byte alignment */ 00194 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); 00195 } 00196 00197 static void 00198 array_types_only_reader_recurse (DBusTypeReader *sub, 00199 DBusTypeReader *parent) 00200 { 00201 base_reader_recurse (sub, parent); 00202 00203 /* point type_pos at the array element type */ 00204 sub->type_pos += 1; 00205 00206 /* Init with values likely to crash things if misused */ 00207 sub->u.array.start_pos = _DBUS_INT_MAX; 00208 sub->array_len_offset = 7; 00209 } 00210 00213 #define ARRAY_READER_LEN_POS(reader) \ 00214 ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4) 00215 00216 static int 00217 array_reader_get_array_len (const DBusTypeReader *reader) 00218 { 00219 dbus_uint32_t array_len; 00220 int len_pos; 00221 00222 len_pos = ARRAY_READER_LEN_POS (reader); 00223 00224 _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos); 00225 array_len = _dbus_unpack_uint32 (reader->byte_order, 00226 _dbus_string_get_const_data_len (reader->value_str, len_pos, 4)); 00227 00228 #if RECURSIVE_MARSHAL_READ_TRACE 00229 _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n", 00230 reader, len_pos, array_len, reader->array_len_offset); 00231 #endif 00232 00233 _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8); 00234 00235 return array_len; 00236 } 00237 00238 static void 00239 array_reader_recurse (DBusTypeReader *sub, 00240 DBusTypeReader *parent) 00241 { 00242 int alignment; 00243 int len_pos; 00244 00245 array_types_only_reader_recurse (sub, parent); 00246 00247 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); 00248 00249 len_pos = sub->value_pos; 00250 00251 sub->value_pos += 4; /* for the length */ 00252 00253 alignment = element_type_get_alignment (sub->type_str, 00254 sub->type_pos); 00255 00256 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); 00257 00258 sub->u.array.start_pos = sub->value_pos; 00259 _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */ 00260 sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4); 00261 00262 #if RECURSIVE_MARSHAL_READ_TRACE 00263 _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n", 00264 sub, 00265 sub->u.array.start_pos, 00266 sub->array_len_offset, 00267 array_reader_get_array_len (sub), 00268 _dbus_type_to_string (_dbus_first_type_in_signature (sub->type_str, 00269 sub->type_pos))); 00270 #endif 00271 } 00272 00273 static void 00274 variant_reader_recurse (DBusTypeReader *sub, 00275 DBusTypeReader *parent) 00276 { 00277 int sig_len; 00278 int contained_alignment; 00279 00280 base_reader_recurse (sub, parent); 00281 00282 /* Variant is 1 byte sig length (without nul), signature with nul, 00283 * padding to 8-boundary, then values 00284 */ 00285 00286 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos); 00287 00288 sub->type_str = sub->value_str; 00289 sub->type_pos = sub->value_pos + 1; 00290 00291 sub->value_pos = sub->type_pos + sig_len + 1; 00292 00293 contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (sub->type_str, 00294 sub->type_pos)); 00295 00296 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); 00297 00298 #if RECURSIVE_MARSHAL_READ_TRACE 00299 _dbus_verbose (" type reader %p variant containing '%s'\n", 00300 sub, 00301 _dbus_string_get_const_data_len (sub->type_str, 00302 sub->type_pos, 0)); 00303 #endif 00304 } 00305 00306 static dbus_bool_t 00307 array_reader_check_finished (const DBusTypeReader *reader) 00308 { 00309 int end_pos; 00310 00311 /* return the array element type if elements remain, and 00312 * TYPE_INVALID otherwise 00313 */ 00314 00315 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); 00316 00317 _dbus_assert (reader->value_pos <= end_pos); 00318 _dbus_assert (reader->value_pos >= reader->u.array.start_pos); 00319 00320 return reader->value_pos == end_pos; 00321 } 00322 00323 static void 00324 skip_one_complete_type (const DBusString *type_str, 00325 int *type_pos) 00326 { 00327 _dbus_type_signature_next (_dbus_string_get_const_data (type_str), 00328 type_pos); 00329 } 00330 00339 void 00340 _dbus_type_signature_next (const char *type_str, 00341 int *type_pos) 00342 { 00343 const unsigned char *p; 00344 const unsigned char *start; 00345 00346 _dbus_assert (type_str != NULL); 00347 _dbus_assert (type_pos != NULL); 00348 00349 start = type_str; 00350 p = start + *type_pos; 00351 00352 _dbus_assert (*p != DBUS_STRUCT_END_CHAR); 00353 _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); 00354 00355 while (*p == DBUS_TYPE_ARRAY) 00356 ++p; 00357 00358 _dbus_assert (*p != DBUS_STRUCT_END_CHAR); 00359 _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); 00360 00361 if (*p == DBUS_STRUCT_BEGIN_CHAR) 00362 { 00363 int depth; 00364 00365 depth = 1; 00366 00367 while (TRUE) 00368 { 00369 _dbus_assert (*p != DBUS_TYPE_INVALID); 00370 00371 ++p; 00372 00373 _dbus_assert (*p != DBUS_TYPE_INVALID); 00374 00375 if (*p == DBUS_STRUCT_BEGIN_CHAR) 00376 depth += 1; 00377 else if (*p == DBUS_STRUCT_END_CHAR) 00378 { 00379 depth -= 1; 00380 if (depth == 0) 00381 { 00382 ++p; 00383 break; 00384 } 00385 } 00386 } 00387 } 00388 else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) 00389 { 00390 int depth; 00391 00392 depth = 1; 00393 00394 while (TRUE) 00395 { 00396 _dbus_assert (*p != DBUS_TYPE_INVALID); 00397 00398 ++p; 00399 00400 _dbus_assert (*p != DBUS_TYPE_INVALID); 00401 00402 if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) 00403 depth += 1; 00404 else if (*p == DBUS_DICT_ENTRY_END_CHAR) 00405 { 00406 depth -= 1; 00407 if (depth == 0) 00408 { 00409 ++p; 00410 break; 00411 } 00412 } 00413 } 00414 } 00415 else 00416 { 00417 ++p; 00418 } 00419 00420 *type_pos = (int) (p - start); 00421 } 00422 00423 static int 00424 find_len_of_complete_type (const DBusString *type_str, 00425 int type_pos) 00426 { 00427 int end; 00428 00429 end = type_pos; 00430 00431 skip_one_complete_type (type_str, &end); 00432 00433 return end - type_pos; 00434 } 00435 00436 static void 00437 base_reader_next (DBusTypeReader *reader, 00438 int current_type) 00439 { 00440 switch (current_type) 00441 { 00442 case DBUS_TYPE_DICT_ENTRY: 00443 case DBUS_TYPE_STRUCT: 00444 case DBUS_TYPE_VARIANT: 00445 /* Scan forward over the entire container contents */ 00446 { 00447 DBusTypeReader sub; 00448 00449 if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT) 00450 ; 00451 else 00452 { 00453 /* Recurse into the struct or variant */ 00454 _dbus_type_reader_recurse (reader, &sub); 00455 00456 /* Skip everything in this subreader */ 00457 while (_dbus_type_reader_next (&sub)) 00458 { 00459 /* nothing */; 00460 } 00461 } 00462 if (!reader->klass->types_only) 00463 reader->value_pos = sub.value_pos; 00464 00465 /* Now we are at the end of this container; for variants, the 00466 * subreader's type_pos is totally inapplicable (it's in the 00467 * value string) but we know that we increment by one past the 00468 * DBUS_TYPE_VARIANT 00469 */ 00470 if (current_type == DBUS_TYPE_VARIANT) 00471 reader->type_pos += 1; 00472 else 00473 reader->type_pos = sub.type_pos; 00474 } 00475 break; 00476 00477 case DBUS_TYPE_ARRAY: 00478 { 00479 if (!reader->klass->types_only) 00480 _dbus_marshal_skip_array (reader->value_str, 00481 _dbus_first_type_in_signature (reader->type_str, 00482 reader->type_pos + 1), 00483 reader->byte_order, 00484 &reader->value_pos); 00485 00486 skip_one_complete_type (reader->type_str, &reader->type_pos); 00487 } 00488 break; 00489 00490 default: 00491 if (!reader->klass->types_only) 00492 _dbus_marshal_skip_basic (reader->value_str, 00493 current_type, reader->byte_order, 00494 &reader->value_pos); 00495 00496 reader->type_pos += 1; 00497 break; 00498 } 00499 } 00500 00501 static void 00502 struct_reader_next (DBusTypeReader *reader, 00503 int current_type) 00504 { 00505 int t; 00506 00507 base_reader_next (reader, current_type); 00508 00509 /* for STRUCT containers we return FALSE at the end of the struct, 00510 * for INVALID we return FALSE at the end of the signature. 00511 * In both cases we arrange for get_current_type() to return INVALID 00512 * which is defined to happen iff we're at the end (no more next()) 00513 */ 00514 t = _dbus_string_get_byte (reader->type_str, reader->type_pos); 00515 if (t == DBUS_STRUCT_END_CHAR) 00516 { 00517 reader->type_pos += 1; 00518 reader->finished = TRUE; 00519 } 00520 } 00521 00522 static void 00523 dict_entry_reader_next (DBusTypeReader *reader, 00524 int current_type) 00525 { 00526 int t; 00527 00528 base_reader_next (reader, current_type); 00529 00530 /* for STRUCT containers we return FALSE at the end of the struct, 00531 * for INVALID we return FALSE at the end of the signature. 00532 * In both cases we arrange for get_current_type() to return INVALID 00533 * which is defined to happen iff we're at the end (no more next()) 00534 */ 00535 t = _dbus_string_get_byte (reader->type_str, reader->type_pos); 00536 if (t == DBUS_DICT_ENTRY_END_CHAR) 00537 { 00538 reader->type_pos += 1; 00539 reader->finished = TRUE; 00540 } 00541 } 00542 00543 static void 00544 array_types_only_reader_next (DBusTypeReader *reader, 00545 int current_type) 00546 { 00547 /* We have one "element" to be iterated over 00548 * in each array, which is its element type. 00549 * So the finished flag indicates whether we've 00550 * iterated over it yet or not. 00551 */ 00552 reader->finished = TRUE; 00553 } 00554 00555 static void 00556 array_reader_next (DBusTypeReader *reader, 00557 int current_type) 00558 { 00559 /* Skip one array element */ 00560 int end_pos; 00561 00562 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); 00563 00564 #if RECURSIVE_MARSHAL_READ_TRACE 00565 _dbus_verbose (" reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", 00566 reader, 00567 reader->u.array.start_pos, 00568 end_pos, reader->value_pos, 00569 _dbus_type_to_string (current_type)); 00570 #endif 00571 00572 _dbus_assert (reader->value_pos < end_pos); 00573 _dbus_assert (reader->value_pos >= reader->u.array.start_pos); 00574 00575 switch (_dbus_first_type_in_signature (reader->type_str, 00576 reader->type_pos)) 00577 { 00578 case DBUS_TYPE_DICT_ENTRY: 00579 case DBUS_TYPE_STRUCT: 00580 case DBUS_TYPE_VARIANT: 00581 { 00582 DBusTypeReader sub; 00583 00584 /* Recurse into the struct or variant */ 00585 _dbus_type_reader_recurse (reader, &sub); 00586 00587 /* Skip everything in this element */ 00588 while (_dbus_type_reader_next (&sub)) 00589 { 00590 /* nothing */; 00591 } 00592 00593 /* Now we are at the end of this element */ 00594 reader->value_pos = sub.value_pos; 00595 } 00596 break; 00597 00598 case DBUS_TYPE_ARRAY: 00599 { 00600 _dbus_marshal_skip_array (reader->value_str, 00601 _dbus_first_type_in_signature (reader->type_str, 00602 reader->type_pos + 1), 00603 reader->byte_order, 00604 &reader->value_pos); 00605 } 00606 break; 00607 00608 default: 00609 { 00610 _dbus_marshal_skip_basic (reader->value_str, 00611 current_type, reader->byte_order, 00612 &reader->value_pos); 00613 } 00614 break; 00615 } 00616 00617 #if RECURSIVE_MARSHAL_READ_TRACE 00618 _dbus_verbose (" reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", 00619 reader, 00620 reader->u.array.start_pos, 00621 end_pos, reader->value_pos, 00622 _dbus_type_to_string (current_type)); 00623 #endif 00624 00625 _dbus_assert (reader->value_pos <= end_pos); 00626 00627 if (reader->value_pos == end_pos) 00628 { 00629 skip_one_complete_type (reader->type_str, 00630 &reader->type_pos); 00631 } 00632 } 00633 00634 static const DBusTypeReaderClass body_reader_class = { 00635 "body", 0, 00636 FALSE, 00637 NULL, /* body is always toplevel, so doesn't get recursed into */ 00638 NULL, 00639 base_reader_next 00640 }; 00641 00642 static const DBusTypeReaderClass body_types_only_reader_class = { 00643 "body types", 1, 00644 TRUE, 00645 NULL, /* body is always toplevel, so doesn't get recursed into */ 00646 NULL, 00647 base_reader_next 00648 }; 00649 00650 static const DBusTypeReaderClass struct_reader_class = { 00651 "struct", 2, 00652 FALSE, 00653 struct_or_dict_entry_reader_recurse, 00654 NULL, 00655 struct_reader_next 00656 }; 00657 00658 static const DBusTypeReaderClass struct_types_only_reader_class = { 00659 "struct types", 3, 00660 TRUE, 00661 struct_or_dict_entry_types_only_reader_recurse, 00662 NULL, 00663 struct_reader_next 00664 }; 00665 00666 static const DBusTypeReaderClass dict_entry_reader_class = { 00667 "dict_entry", 4, 00668 FALSE, 00669 struct_or_dict_entry_reader_recurse, 00670 NULL, 00671 dict_entry_reader_next 00672 }; 00673 00674 static const DBusTypeReaderClass dict_entry_types_only_reader_class = { 00675 "dict_entry types", 5, 00676 TRUE, 00677 struct_or_dict_entry_types_only_reader_recurse, 00678 NULL, 00679 dict_entry_reader_next 00680 }; 00681 00682 static const DBusTypeReaderClass array_reader_class = { 00683 "array", 6, 00684 FALSE, 00685 array_reader_recurse, 00686 array_reader_check_finished, 00687 array_reader_next 00688 }; 00689 00690 static const DBusTypeReaderClass array_types_only_reader_class = { 00691 "array types", 7, 00692 TRUE, 00693 array_types_only_reader_recurse, 00694 NULL, 00695 array_types_only_reader_next 00696 }; 00697 00698 static const DBusTypeReaderClass variant_reader_class = { 00699 "variant", 8, 00700 FALSE, 00701 variant_reader_recurse, 00702 NULL, 00703 base_reader_next 00704 }; 00705 00706 #ifndef DBUS_DISABLE_ASSERT 00707 static const DBusTypeReaderClass * const 00708 all_reader_classes[] = { 00709 &body_reader_class, 00710 &body_types_only_reader_class, 00711 &struct_reader_class, 00712 &struct_types_only_reader_class, 00713 &dict_entry_reader_class, 00714 &dict_entry_types_only_reader_class, 00715 &array_reader_class, 00716 &array_types_only_reader_class, 00717 &variant_reader_class 00718 }; 00719 #endif 00720 00731 void 00732 _dbus_type_reader_init (DBusTypeReader *reader, 00733 int byte_order, 00734 const DBusString *type_str, 00735 int type_pos, 00736 const DBusString *value_str, 00737 int value_pos) 00738 { 00739 reader->klass = &body_reader_class; 00740 00741 reader_init (reader, byte_order, type_str, type_pos, 00742 value_str, value_pos); 00743 00744 #if RECURSIVE_MARSHAL_READ_TRACE 00745 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n", 00746 reader, reader->type_pos, reader->value_pos, 00747 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); 00748 #endif 00749 } 00750 00759 void 00760 _dbus_type_reader_init_types_only (DBusTypeReader *reader, 00761 const DBusString *type_str, 00762 int type_pos) 00763 { 00764 reader->klass = &body_types_only_reader_class; 00765 00766 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */, 00767 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */); 00768 00769 #if RECURSIVE_MARSHAL_READ_TRACE 00770 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n", 00771 reader, reader->type_pos, 00772 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); 00773 #endif 00774 } 00775 00784 int 00785 _dbus_type_reader_get_current_type (const DBusTypeReader *reader) 00786 { 00787 int t; 00788 00789 if (reader->finished || 00790 (reader->klass->check_finished && 00791 (* reader->klass->check_finished) (reader))) 00792 t = DBUS_TYPE_INVALID; 00793 else 00794 t = _dbus_first_type_in_signature (reader->type_str, 00795 reader->type_pos); 00796 00797 _dbus_assert (t != DBUS_STRUCT_END_CHAR); 00798 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR); 00799 _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR); 00800 _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR); 00801 00802 #if 0 00803 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n", 00804 reader, reader->type_pos, 00805 _dbus_type_to_string (t)); 00806 #endif 00807 00808 return t; 00809 } 00810 00819 int 00820 _dbus_type_reader_get_element_type (const DBusTypeReader *reader) 00821 { 00822 int element_type; 00823 00824 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY); 00825 00826 element_type = _dbus_first_type_in_signature (reader->type_str, 00827 reader->type_pos + 1); 00828 00829 return element_type; 00830 } 00831 00836 int 00837 _dbus_type_reader_get_value_pos (const DBusTypeReader *reader) 00838 { 00839 return reader->value_pos; 00840 } 00841 00851 void 00852 _dbus_type_reader_read_raw (const DBusTypeReader *reader, 00853 const unsigned char **value_location) 00854 { 00855 _dbus_assert (!reader->klass->types_only); 00856 00857 *value_location = _dbus_string_get_const_data_len (reader->value_str, 00858 reader->value_pos, 00859 0); 00860 } 00861 00868 void 00869 _dbus_type_reader_read_basic (const DBusTypeReader *reader, 00870 void *value) 00871 { 00872 int t; 00873 00874 _dbus_assert (!reader->klass->types_only); 00875 00876 t = _dbus_type_reader_get_current_type (reader); 00877 00878 _dbus_marshal_read_basic (reader->value_str, 00879 reader->value_pos, 00880 t, value, 00881 reader->byte_order, 00882 NULL); 00883 00884 00885 #if RECURSIVE_MARSHAL_READ_TRACE 00886 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n", 00887 reader, reader->type_pos, reader->value_pos, 00888 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); 00889 #endif 00890 } 00891 00898 int 00899 _dbus_type_reader_get_array_length (const DBusTypeReader *reader) 00900 { 00901 _dbus_assert (!reader->klass->types_only); 00902 _dbus_assert (reader->klass == &array_reader_class); 00903 00904 return array_reader_get_array_len (reader); 00905 } 00906 00922 void 00923 _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, 00924 void *value, 00925 int *n_elements) 00926 { 00927 int element_type; 00928 int end_pos; 00929 int remaining_len; 00930 int alignment; 00931 int total_len; 00932 00933 _dbus_assert (!reader->klass->types_only); 00934 _dbus_assert (reader->klass == &array_reader_class); 00935 00936 element_type = _dbus_first_type_in_signature (reader->type_str, 00937 reader->type_pos); 00938 00939 _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */ 00940 _dbus_assert (dbus_type_is_fixed (element_type)); 00941 00942 alignment = _dbus_type_get_alignment (element_type); 00943 00944 _dbus_assert (reader->value_pos >= reader->u.array.start_pos); 00945 00946 total_len = array_reader_get_array_len (reader); 00947 end_pos = reader->u.array.start_pos + total_len; 00948 remaining_len = end_pos - reader->value_pos; 00949 00950 #if RECURSIVE_MARSHAL_READ_TRACE 00951 _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n", 00952 end_pos, total_len, remaining_len, reader->value_pos); 00953 #endif 00954 00955 _dbus_assert (remaining_len <= total_len); 00956 00957 if (remaining_len == 0) 00958 *(const DBusBasicValue**) value = NULL; 00959 else 00960 *(const DBusBasicValue**) value = 00961 (void*) _dbus_string_get_const_data_len (reader->value_str, 00962 reader->value_pos, 00963 remaining_len); 00964 00965 *n_elements = remaining_len / alignment; 00966 _dbus_assert ((remaining_len % alignment) == 0); 00967 00968 #if RECURSIVE_MARSHAL_READ_TRACE 00969 _dbus_verbose (" type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n", 00970 reader, reader->type_pos, reader->value_pos, 00971 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); 00972 #endif 00973 } 00974 00987 void 00988 _dbus_type_reader_recurse (DBusTypeReader *reader, 00989 DBusTypeReader *sub) 00990 { 00991 int t; 00992 00993 t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos); 00994 00995 switch (t) 00996 { 00997 case DBUS_TYPE_STRUCT: 00998 if (reader->klass->types_only) 00999 sub->klass = &struct_types_only_reader_class; 01000 else 01001 sub->klass = &struct_reader_class; 01002 break; 01003 case DBUS_TYPE_DICT_ENTRY: 01004 if (reader->klass->types_only) 01005 sub->klass = &dict_entry_types_only_reader_class; 01006 else 01007 sub->klass = &dict_entry_reader_class; 01008 break; 01009 case DBUS_TYPE_ARRAY: 01010 if (reader->klass->types_only) 01011 sub->klass = &array_types_only_reader_class; 01012 else 01013 sub->klass = &array_reader_class; 01014 break; 01015 case DBUS_TYPE_VARIANT: 01016 if (reader->klass->types_only) 01017 _dbus_assert_not_reached ("can't recurse into variant typecode"); 01018 else 01019 sub->klass = &variant_reader_class; 01020 break; 01021 default: 01022 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t)); 01023 #ifndef DBUS_DISABLE_CHECKS 01024 if (t == DBUS_TYPE_INVALID) 01025 _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n"); 01026 #endif /* DBUS_DISABLE_CHECKS */ 01027 01028 _dbus_assert_not_reached ("don't yet handle recursing into this type"); 01029 } 01030 01031 _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]); 01032 01033 (* sub->klass->recurse) (sub, reader); 01034 01035 #if RECURSIVE_MARSHAL_READ_TRACE 01036 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n", 01037 sub, sub->type_pos, sub->value_pos, 01038 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0)); 01039 #endif 01040 } 01041 01050 dbus_bool_t 01051 _dbus_type_reader_next (DBusTypeReader *reader) 01052 { 01053 int t; 01054 01055 t = _dbus_type_reader_get_current_type (reader); 01056 01057 #if RECURSIVE_MARSHAL_READ_TRACE 01058 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", 01059 reader, reader->type_pos, reader->value_pos, 01060 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), 01061 _dbus_type_to_string (t)); 01062 #endif 01063 01064 if (t == DBUS_TYPE_INVALID) 01065 return FALSE; 01066 01067 (* reader->klass->next) (reader, t); 01068 01069 #if RECURSIVE_MARSHAL_READ_TRACE 01070 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", 01071 reader, reader->type_pos, reader->value_pos, 01072 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), 01073 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader))); 01074 #endif 01075 01076 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID; 01077 } 01078 01090 dbus_bool_t 01091 _dbus_type_reader_has_next (const DBusTypeReader *reader) 01092 { 01093 /* Not efficient but works for now. */ 01094 DBusTypeReader copy; 01095 01096 copy = *reader; 01097 return _dbus_type_reader_next (©); 01098 } 01099 01121 void 01122 _dbus_type_reader_get_signature (const DBusTypeReader *reader, 01123 const DBusString **str_p, 01124 int *start_p, 01125 int *len_p) 01126 { 01127 *str_p = reader->type_str; 01128 *start_p = reader->type_pos; 01129 *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos); 01130 } 01131 01132 typedef struct 01133 { 01134 DBusString replacement; 01135 int padding; 01136 } ReplacementBlock; 01137 01138 static dbus_bool_t 01139 replacement_block_init (ReplacementBlock *block, 01140 DBusTypeReader *reader) 01141 { 01142 if (!_dbus_string_init (&block->replacement)) 01143 return FALSE; 01144 01145 /* % 8 is the padding to have the same align properties in 01146 * our replacement string as we do at the position being replaced 01147 */ 01148 block->padding = reader->value_pos % 8; 01149 01150 if (!_dbus_string_lengthen (&block->replacement, block->padding)) 01151 goto oom; 01152 01153 return TRUE; 01154 01155 oom: 01156 _dbus_string_free (&block->replacement); 01157 return FALSE; 01158 } 01159 01160 static dbus_bool_t 01161 replacement_block_replace (ReplacementBlock *block, 01162 DBusTypeReader *reader, 01163 const DBusTypeReader *realign_root) 01164 { 01165 DBusTypeWriter writer; 01166 DBusTypeReader realign_reader; 01167 DBusList *fixups; 01168 int orig_len; 01169 01170 _dbus_assert (realign_root != NULL); 01171 01172 orig_len = _dbus_string_get_length (&block->replacement); 01173 01174 realign_reader = *realign_root; 01175 01176 #if RECURSIVE_MARSHAL_WRITE_TRACE 01177 _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n", 01178 &writer, _dbus_string_get_length (&block->replacement)); 01179 #endif 01180 _dbus_type_writer_init_values_only (&writer, 01181 realign_reader.byte_order, 01182 realign_reader.type_str, 01183 realign_reader.type_pos, 01184 &block->replacement, 01185 _dbus_string_get_length (&block->replacement)); 01186 01187 _dbus_assert (realign_reader.value_pos <= reader->value_pos); 01188 01189 #if RECURSIVE_MARSHAL_WRITE_TRACE 01190 _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n", 01191 realign_reader.value_pos, &writer, reader->value_pos); 01192 #endif 01193 fixups = NULL; 01194 if (!_dbus_type_writer_write_reader_partial (&writer, 01195 &realign_reader, 01196 reader, 01197 block->padding, 01198 _dbus_string_get_length (&block->replacement) - block->padding, 01199 &fixups)) 01200 goto oom; 01201 01202 #if RECURSIVE_MARSHAL_WRITE_TRACE 01203 _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding, 01204 _dbus_string_get_length (&block->replacement) - block->padding); 01205 _dbus_verbose_bytes_of_string (&block->replacement, block->padding, 01206 _dbus_string_get_length (&block->replacement) - block->padding); 01207 _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n", 01208 reader->value_pos, reader->value_pos % 8, 01209 realign_reader.value_pos - reader->value_pos, 01210 realign_reader.value_pos); 01211 _dbus_verbose_bytes_of_string (reader->value_str, 01212 reader->value_pos, 01213 realign_reader.value_pos - reader->value_pos); 01214 #endif 01215 01216 /* Move the replacement into position 01217 * (realign_reader should now be at the end of the block to be replaced) 01218 */ 01219 if (!_dbus_string_replace_len (&block->replacement, block->padding, 01220 _dbus_string_get_length (&block->replacement) - block->padding, 01221 (DBusString*) reader->value_str, 01222 reader->value_pos, 01223 realign_reader.value_pos - reader->value_pos)) 01224 goto oom; 01225 01226 /* Process our fixups now that we can't have an OOM error */ 01227 apply_and_free_fixups (&fixups, reader); 01228 01229 return TRUE; 01230 01231 oom: 01232 _dbus_string_set_length (&block->replacement, orig_len); 01233 free_fixups (&fixups); 01234 return FALSE; 01235 } 01236 01237 static void 01238 replacement_block_free (ReplacementBlock *block) 01239 { 01240 _dbus_string_free (&block->replacement); 01241 } 01242 01243 /* In the variable-length case, we have to fix alignment after we insert. 01244 * The strategy is as follows: 01245 * 01246 * - pad a new string to have the same alignment as the 01247 * start of the current basic value 01248 * - write the new basic value 01249 * - copy from the original reader to the new string, 01250 * which will fix the alignment of types following 01251 * the new value 01252 * - this copy has to start at realign_root, 01253 * but not really write anything until it 01254 * passes the value being set 01255 * - as an optimization, we can stop copying 01256 * when the source and dest values are both 01257 * on an 8-boundary, since we know all following 01258 * padding and alignment will be identical 01259 * - copy the new string back to the original 01260 * string, replacing the relevant part of the 01261 * original string 01262 * - now any arrays in the original string that 01263 * contained the replaced string may have the 01264 * wrong length; so we have to fix that 01265 */ 01266 static dbus_bool_t 01267 reader_set_basic_variable_length (DBusTypeReader *reader, 01268 int current_type, 01269 const void *value, 01270 const DBusTypeReader *realign_root) 01271 { 01272 dbus_bool_t retval; 01273 ReplacementBlock block; 01274 DBusTypeWriter writer; 01275 01276 _dbus_assert (realign_root != NULL); 01277 01278 retval = FALSE; 01279 01280 if (!replacement_block_init (&block, reader)) 01281 return FALSE; 01282 01283 /* Write the new basic value */ 01284 #if RECURSIVE_MARSHAL_WRITE_TRACE 01285 _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n", 01286 &writer, _dbus_string_get_length (&block.replacement)); 01287 #endif 01288 _dbus_type_writer_init_values_only (&writer, 01289 reader->byte_order, 01290 reader->type_str, 01291 reader->type_pos, 01292 &block.replacement, 01293 _dbus_string_get_length (&block.replacement)); 01294 #if RECURSIVE_MARSHAL_WRITE_TRACE 01295 _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer); 01296 #endif 01297 if (!_dbus_type_writer_write_basic (&writer, current_type, value)) 01298 goto out; 01299 01300 if (!replacement_block_replace (&block, 01301 reader, 01302 realign_root)) 01303 goto out; 01304 01305 retval = TRUE; 01306 01307 out: 01308 replacement_block_free (&block); 01309 return retval; 01310 } 01311 01312 static void 01313 reader_set_basic_fixed_length (DBusTypeReader *reader, 01314 int current_type, 01315 const void *value) 01316 { 01317 _dbus_marshal_set_basic ((DBusString*) reader->value_str, 01318 reader->value_pos, 01319 current_type, 01320 value, 01321 reader->byte_order, 01322 NULL, NULL); 01323 } 01324 01359 dbus_bool_t 01360 _dbus_type_reader_set_basic (DBusTypeReader *reader, 01361 const void *value, 01362 const DBusTypeReader *realign_root) 01363 { 01364 int current_type; 01365 01366 _dbus_assert (!reader->klass->types_only); 01367 _dbus_assert (reader->value_str == realign_root->value_str); 01368 _dbus_assert (reader->value_pos >= realign_root->value_pos); 01369 01370 current_type = _dbus_type_reader_get_current_type (reader); 01371 01372 #if RECURSIVE_MARSHAL_WRITE_TRACE 01373 _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", 01374 reader, reader->type_pos, reader->value_pos, 01375 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), 01376 realign_root, 01377 realign_root ? realign_root->value_pos : -1, 01378 _dbus_type_to_string (current_type)); 01379 _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos, 01380 _dbus_string_get_length (realign_root->value_str) - 01381 realign_root->value_pos); 01382 #endif 01383 01384 _dbus_assert (dbus_type_is_basic (current_type)); 01385 01386 if (dbus_type_is_fixed (current_type)) 01387 { 01388 reader_set_basic_fixed_length (reader, current_type, value); 01389 return TRUE; 01390 } 01391 else 01392 { 01393 _dbus_assert (realign_root != NULL); 01394 return reader_set_basic_variable_length (reader, current_type, 01395 value, realign_root); 01396 } 01397 } 01398 01416 dbus_bool_t 01417 _dbus_type_reader_delete (DBusTypeReader *reader, 01418 const DBusTypeReader *realign_root) 01419 { 01420 dbus_bool_t retval; 01421 ReplacementBlock block; 01422 01423 _dbus_assert (realign_root != NULL); 01424 _dbus_assert (reader->klass == &array_reader_class); 01425 01426 retval = FALSE; 01427 01428 if (!replacement_block_init (&block, reader)) 01429 return FALSE; 01430 01431 if (!replacement_block_replace (&block, 01432 reader, 01433 realign_root)) 01434 goto out; 01435 01436 retval = TRUE; 01437 01438 out: 01439 replacement_block_free (&block); 01440 return retval; 01441 } 01442 01443 /* 01444 * Compares two readers, which must be iterating over the same value data. 01445 * Returns #TRUE if the first parameter is further along than the second parameter. 01446 * 01447 * @param lhs left-hand-side (first) parameter 01448 * @param rhs left-hand-side (first) parameter 01449 * @returns whether lhs is greater than rhs 01450 */ 01451 static dbus_bool_t 01452 _dbus_type_reader_greater_than (const DBusTypeReader *lhs, 01453 const DBusTypeReader *rhs) 01454 { 01455 _dbus_assert (lhs->value_str == rhs->value_str); 01456 01457 return lhs->value_pos > rhs->value_pos; 01458 } 01459 01460 /* 01461 * 01462 * 01463 * DBusTypeWriter 01464 * 01465 * 01466 * 01467 */ 01468 01489 void 01490 _dbus_type_writer_init (DBusTypeWriter *writer, 01491 int byte_order, 01492 DBusString *type_str, 01493 int type_pos, 01494 DBusString *value_str, 01495 int value_pos) 01496 { 01497 writer->byte_order = byte_order; 01498 writer->type_str = type_str; 01499 writer->type_pos = type_pos; 01500 writer->value_str = value_str; 01501 writer->value_pos = value_pos; 01502 writer->container_type = DBUS_TYPE_INVALID; 01503 writer->type_pos_is_expectation = FALSE; 01504 writer->enabled = TRUE; 01505 01506 #if RECURSIVE_MARSHAL_WRITE_TRACE 01507 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer, 01508 writer->type_str ? 01509 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : 01510 "unknown"); 01511 #endif 01512 } 01513 01524 void 01525 _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, 01526 int byte_order, 01527 DBusString *value_str, 01528 int value_pos) 01529 { 01530 _dbus_type_writer_init (writer, byte_order, 01531 NULL, 0, value_str, value_pos); 01532 } 01533 01542 void 01543 _dbus_type_writer_add_types (DBusTypeWriter *writer, 01544 DBusString *type_str, 01545 int type_pos) 01546 { 01547 if (writer->type_str == NULL) /* keeps us from using this as setter */ 01548 { 01549 writer->type_str = type_str; 01550 writer->type_pos = type_pos; 01551 } 01552 } 01553 01559 void 01560 _dbus_type_writer_remove_types (DBusTypeWriter *writer) 01561 { 01562 writer->type_str = NULL; 01563 writer->type_pos = -1; 01564 } 01565 01580 void 01581 _dbus_type_writer_init_values_only (DBusTypeWriter *writer, 01582 int byte_order, 01583 const DBusString *type_str, 01584 int type_pos, 01585 DBusString *value_str, 01586 int value_pos) 01587 { 01588 _dbus_type_writer_init (writer, byte_order, 01589 (DBusString*)type_str, type_pos, 01590 value_str, value_pos); 01591 01592 writer->type_pos_is_expectation = TRUE; 01593 } 01594 01595 static dbus_bool_t 01596 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer, 01597 int type, 01598 const void *value) 01599 { 01600 if (writer->enabled) 01601 return _dbus_marshal_write_basic (writer->value_str, 01602 writer->value_pos, 01603 type, 01604 value, 01605 writer->byte_order, 01606 &writer->value_pos); 01607 else 01608 return TRUE; 01609 } 01610 01611 /* If our parent is an array, things are a little bit complicated. 01612 * 01613 * The parent must have a complete element type, such as 01614 * "i" or "aai" or "(ii)" or "a(ii)". There can't be 01615 * unclosed parens, or an "a" with no following type. 01616 * 01617 * To recurse, the only allowed operation is to recurse into the 01618 * first type in the element type. So for "i" you can't recurse, for 01619 * "ai" you can recurse into the array, for "(ii)" you can recurse 01620 * into the struct. 01621 * 01622 * If you recurse into the array for "ai", then you must specify 01623 * "i" for the element type of the array you recurse into. 01624 * 01625 * While inside an array at any level, we need to avoid writing to 01626 * type_str, since the type only appears once for the whole array, 01627 * it does not appear for each array element. 01628 * 01629 * While inside an array type_pos points to the expected next 01630 * typecode, rather than the next place we could write a typecode. 01631 */ 01632 static void 01633 writer_recurse_init_and_check (DBusTypeWriter *writer, 01634 int container_type, 01635 DBusTypeWriter *sub) 01636 { 01637 _dbus_type_writer_init (sub, 01638 writer->byte_order, 01639 writer->type_str, 01640 writer->type_pos, 01641 writer->value_str, 01642 writer->value_pos); 01643 01644 sub->container_type = container_type; 01645 01646 if (writer->type_pos_is_expectation || 01647 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT)) 01648 sub->type_pos_is_expectation = TRUE; 01649 else 01650 sub->type_pos_is_expectation = FALSE; 01651 01652 sub->enabled = writer->enabled; 01653 01654 #ifndef DBUS_DISABLE_CHECKS 01655 if (writer->type_pos_is_expectation && writer->type_str) 01656 { 01657 int expected; 01658 01659 expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos); 01660 01661 if (expected != sub->container_type) 01662 { 01663 if (expected != DBUS_TYPE_INVALID) 01664 _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n" 01665 "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", 01666 _dbus_type_to_string (sub->container_type), 01667 _dbus_type_to_string (expected), 01668 _dbus_string_get_const_data (writer->type_str), writer->type_pos); 01669 else 01670 _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n" 01671 "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", 01672 _dbus_type_to_string (sub->container_type), 01673 _dbus_string_get_const_data (writer->type_str), writer->type_pos); 01674 01675 _dbus_assert_not_reached ("bad array element or variant content written"); 01676 } 01677 } 01678 #endif /* DBUS_DISABLE_CHECKS */ 01679 01680 #if RECURSIVE_MARSHAL_WRITE_TRACE 01681 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n", 01682 writer, 01683 _dbus_type_to_string (writer->container_type), 01684 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, 01685 writer->type_str ? 01686 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : 01687 "unknown", 01688 writer->enabled); 01689 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", 01690 sub, 01691 _dbus_type_to_string (sub->container_type), 01692 sub->type_pos, sub->value_pos, 01693 sub->type_pos_is_expectation, 01694 sub->enabled); 01695 #endif 01696 } 01697 01698 static dbus_bool_t 01699 write_or_verify_typecode (DBusTypeWriter *writer, 01700 int typecode) 01701 { 01702 /* A subwriter inside an array or variant will have type_pos 01703 * pointing to the expected typecode; a writer not inside an array 01704 * or variant has type_pos pointing to the next place to insert a 01705 * typecode. 01706 */ 01707 #if RECURSIVE_MARSHAL_WRITE_TRACE 01708 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n", 01709 writer, writer->type_pos, 01710 writer->type_str ? 01711 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : 01712 "unknown", 01713 writer->enabled); 01714 #endif 01715 01716 if (writer->type_str == NULL) 01717 return TRUE; 01718 01719 if (writer->type_pos_is_expectation) 01720 { 01721 #ifndef DBUS_DISABLE_CHECKS 01722 { 01723 int expected; 01724 01725 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos); 01726 01727 if (expected != typecode) 01728 { 01729 if (expected != DBUS_TYPE_INVALID) 01730 _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n" 01731 "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", 01732 _dbus_type_to_string (expected), _dbus_type_to_string (typecode), 01733 _dbus_string_get_const_data (writer->type_str), writer->type_pos); 01734 else 01735 _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" 01736 "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", 01737 _dbus_type_to_string (typecode), 01738 _dbus_string_get_const_data (writer->type_str), writer->type_pos); 01739 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant"); 01740 } 01741 } 01742 #endif /* DBUS_DISABLE_CHECKS */ 01743 01744 /* if immediately inside an array we'd always be appending an element, 01745 * so the expected type doesn't change; if inside a struct or something 01746 * below an array, we need to move through said struct or something. 01747 */ 01748 if (writer->container_type != DBUS_TYPE_ARRAY) 01749 writer->type_pos += 1; 01750 } 01751 else 01752 { 01753 if (!_dbus_string_insert_byte (writer->type_str, 01754 writer->type_pos, 01755 typecode)) 01756 return FALSE; 01757 01758 writer->type_pos += 1; 01759 } 01760 01761 #if RECURSIVE_MARSHAL_WRITE_TRACE 01762 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n", 01763 writer, writer->type_pos, 01764 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0)); 01765 #endif 01766 01767 return TRUE; 01768 } 01769 01770 static dbus_bool_t 01771 writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer, 01772 int begin_char, 01773 const DBusString *contained_type, 01774 int contained_type_start, 01775 int contained_type_len, 01776 DBusTypeWriter *sub) 01777 { 01778 /* FIXME right now contained_type is ignored; we could probably 01779 * almost trivially fix the code so if it's present we 01780 * write it out and then set type_pos_is_expectation 01781 */ 01782 01783 /* Ensure that we'll be able to add alignment padding and the typecode */ 01784 if (writer->enabled) 01785 { 01786 if (!_dbus_string_alloc_space (sub->value_str, 8)) 01787 return FALSE; 01788 } 01789 01790 if (!write_or_verify_typecode (sub, begin_char)) 01791 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc"); 01792 01793 if (writer->enabled) 01794 { 01795 if (!_dbus_string_insert_bytes (sub->value_str, 01796 sub->value_pos, 01797 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos, 01798 '\0')) 01799 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct"); 01800 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); 01801 } 01802 01803 return TRUE; 01804 } 01805 01806 01807 static dbus_bool_t 01808 writer_recurse_array (DBusTypeWriter *writer, 01809 const DBusString *contained_type, 01810 int contained_type_start, 01811 int contained_type_len, 01812 DBusTypeWriter *sub, 01813 dbus_bool_t is_array_append) 01814 { 01815 dbus_uint32_t value = 0; 01816 int alignment; 01817 int aligned; 01818 01819 #ifndef DBUS_DISABLE_CHECKS 01820 if (writer->container_type == DBUS_TYPE_ARRAY && 01821 writer->type_str) 01822 { 01823 if (!_dbus_string_equal_substring (contained_type, 01824 contained_type_start, 01825 contained_type_len, 01826 writer->type_str, 01827 writer->u.array.element_type_pos + 1)) 01828 { 01829 _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n", 01830 _dbus_string_get_const_data_len (contained_type, 01831 contained_type_start, 01832 contained_type_len)); 01833 _dbus_assert_not_reached ("incompatible type for child array"); 01834 } 01835 } 01836 #endif /* DBUS_DISABLE_CHECKS */ 01837 01838 if (writer->enabled && !is_array_append) 01839 { 01840 /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding 01841 * before array values 01842 */ 01843 if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4)) 01844 return FALSE; 01845 } 01846 01847 if (writer->type_str != NULL) 01848 { 01849 sub->type_pos += 1; /* move to point to the element type, since type_pos 01850 * should be the expected type for further writes 01851 */ 01852 sub->u.array.element_type_pos = sub->type_pos; 01853 } 01854 01855 if (!writer->type_pos_is_expectation) 01856 { 01857 /* sub is a toplevel/outermost array so we need to write the type data */ 01858 01859 /* alloc space for array typecode, element signature */ 01860 if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len)) 01861 return FALSE; 01862 01863 if (!_dbus_string_insert_byte (writer->type_str, 01864 writer->type_pos, 01865 DBUS_TYPE_ARRAY)) 01866 _dbus_assert_not_reached ("failed to insert array typecode after prealloc"); 01867 01868 if (!_dbus_string_copy_len (contained_type, 01869 contained_type_start, contained_type_len, 01870 sub->type_str, 01871 sub->u.array.element_type_pos)) 01872 _dbus_assert_not_reached ("should not have failed to insert array element typecodes"); 01873 } 01874 01875 if (writer->type_str != NULL) 01876 { 01877 /* If the parent is an array, we hold type_pos pointing at the array element type; 01878 * otherwise advance it to reflect the array value we just recursed into 01879 */ 01880 if (writer->container_type != DBUS_TYPE_ARRAY) 01881 writer->type_pos += 1 + contained_type_len; 01882 else 01883 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */ 01884 } 01885 01886 if (writer->enabled) 01887 { 01888 /* Write (or jump over, if is_array_append) the length */ 01889 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); 01890 01891 if (is_array_append) 01892 { 01893 sub->value_pos += 4; 01894 } 01895 else 01896 { 01897 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32, 01898 &value)) 01899 _dbus_assert_not_reached ("should not have failed to insert array len"); 01900 } 01901 01902 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4); 01903 01904 /* Write alignment padding for array elements 01905 * Note that we write the padding *even for empty arrays* 01906 * to avoid wonky special cases 01907 */ 01908 alignment = element_type_get_alignment (contained_type, contained_type_start); 01909 01910 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); 01911 if (aligned != sub->value_pos) 01912 { 01913 if (!is_array_append) 01914 { 01915 if (!_dbus_string_insert_bytes (sub->value_str, 01916 sub->value_pos, 01917 aligned - sub->value_pos, 01918 '\0')) 01919 _dbus_assert_not_reached ("should not have failed to insert alignment padding"); 01920 } 01921 01922 sub->value_pos = aligned; 01923 } 01924 01925 sub->u.array.start_pos = sub->value_pos; 01926 01927 if (is_array_append) 01928 { 01929 dbus_uint32_t len; 01930 01931 _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) == 01932 (unsigned) sub->u.array.len_pos); 01933 len = _dbus_unpack_uint32 (sub->byte_order, 01934 _dbus_string_get_const_data_len (sub->value_str, 01935 sub->u.array.len_pos, 01936 4)); 01937 01938 sub->value_pos += len; 01939 } 01940 } 01941 else 01942 { 01943 /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */ 01944 sub->u.array.len_pos = -1; 01945 sub->u.array.start_pos = sub->value_pos; 01946 } 01947 01948 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos); 01949 _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos); 01950 01951 #if RECURSIVE_MARSHAL_WRITE_TRACE 01952 _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub, 01953 sub->type_str ? 01954 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) : 01955 "unknown", 01956 sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos); 01957 #endif 01958 01959 return TRUE; 01960 } 01961 01962 /* Variant value will normally have: 01963 * 1 byte signature length not including nul 01964 * signature typecodes (nul terminated) 01965 * padding to alignment of contained type 01966 * body according to signature 01967 * 01968 * The signature string can only have a single type 01969 * in it but that type may be complex/recursive. 01970 * 01971 * So a typical variant type with the integer 3 will have these 01972 * octets: 01973 * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3 01974 * 01975 * The main world of hurt for writing out a variant is that the type 01976 * string is the same string as the value string. Which means 01977 * inserting to the type string will move the value_pos; and it means 01978 * that inserting to the type string could break type alignment. 01979 */ 01980 static dbus_bool_t 01981 writer_recurse_variant (DBusTypeWriter *writer, 01982 const DBusString *contained_type, 01983 int contained_type_start, 01984 int contained_type_len, 01985 DBusTypeWriter *sub) 01986 { 01987 int contained_alignment; 01988 01989 if (writer->enabled) 01990 { 01991 /* Allocate space for the worst case, which is 1 byte sig 01992 * length, nul byte at end of sig, and 7 bytes padding to 01993 * 8-boundary. 01994 */ 01995 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9)) 01996 return FALSE; 01997 } 01998 01999 /* write VARIANT typecode to the parent's type string */ 02000 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT)) 02001 return FALSE; 02002 02003 /* If not enabled, mark that we have no type_str anymore ... */ 02004 02005 if (!writer->enabled) 02006 { 02007 sub->type_str = NULL; 02008 sub->type_pos = -1; 02009 02010 return TRUE; 02011 } 02012 02013 /* If we're enabled then continue ... */ 02014 02015 if (!_dbus_string_insert_byte (sub->value_str, 02016 sub->value_pos, 02017 contained_type_len)) 02018 _dbus_assert_not_reached ("should not have failed to insert variant type sig len"); 02019 02020 sub->value_pos += 1; 02021 02022 /* Here we switch over to the expected type sig we're about to write */ 02023 sub->type_str = sub->value_str; 02024 sub->type_pos = sub->value_pos; 02025 02026 if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len, 02027 sub->value_str, sub->value_pos)) 02028 _dbus_assert_not_reached ("should not have failed to insert variant type sig"); 02029 02030 sub->value_pos += contained_type_len; 02031 02032 if (!_dbus_string_insert_byte (sub->value_str, 02033 sub->value_pos, 02034 DBUS_TYPE_INVALID)) 02035 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination"); 02036 02037 sub->value_pos += 1; 02038 02039 contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start)); 02040 02041 if (!_dbus_string_insert_bytes (sub->value_str, 02042 sub->value_pos, 02043 _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos, 02044 '\0')) 02045 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body"); 02046 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); 02047 02048 return TRUE; 02049 } 02050 02051 static dbus_bool_t 02052 _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer, 02053 int container_type, 02054 const DBusString *contained_type, 02055 int contained_type_start, 02056 int contained_type_len, 02057 DBusTypeWriter *sub, 02058 dbus_bool_t is_array_append) 02059 { 02060 writer_recurse_init_and_check (writer, container_type, sub); 02061 02062 switch (container_type) 02063 { 02064 case DBUS_TYPE_STRUCT: 02065 return writer_recurse_struct_or_dict_entry (writer, 02066 DBUS_STRUCT_BEGIN_CHAR, 02067 contained_type, 02068 contained_type_start, contained_type_len, 02069 sub); 02070 break; 02071 case DBUS_TYPE_DICT_ENTRY: 02072 return writer_recurse_struct_or_dict_entry (writer, 02073 DBUS_DICT_ENTRY_BEGIN_CHAR, 02074 contained_type, 02075 contained_type_start, contained_type_len, 02076 sub); 02077 break; 02078 case DBUS_TYPE_ARRAY: 02079 return writer_recurse_array (writer, 02080 contained_type, contained_type_start, contained_type_len, 02081 sub, is_array_append); 02082 break; 02083 case DBUS_TYPE_VARIANT: 02084 return writer_recurse_variant (writer, 02085 contained_type, contained_type_start, contained_type_len, 02086 sub); 02087 break; 02088 default: 02089 _dbus_assert_not_reached ("tried to recurse into type that doesn't support that"); 02090 return FALSE; 02091 break; 02092 } 02093 } 02094 02105 dbus_bool_t 02106 _dbus_type_writer_recurse (DBusTypeWriter *writer, 02107 int container_type, 02108 const DBusString *contained_type, 02109 int contained_type_start, 02110 DBusTypeWriter *sub) 02111 { 02112 int contained_type_len; 02113 02114 if (contained_type) 02115 contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); 02116 else 02117 contained_type_len = 0; 02118 02119 return _dbus_type_writer_recurse_contained_len (writer, container_type, 02120 contained_type, 02121 contained_type_start, 02122 contained_type_len, 02123 sub, 02124 FALSE); 02125 } 02126 02139 dbus_bool_t 02140 _dbus_type_writer_append_array (DBusTypeWriter *writer, 02141 const DBusString *contained_type, 02142 int contained_type_start, 02143 DBusTypeWriter *sub) 02144 { 02145 int contained_type_len; 02146 02147 if (contained_type) 02148 contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); 02149 else 02150 contained_type_len = 0; 02151 02152 return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY, 02153 contained_type, 02154 contained_type_start, 02155 contained_type_len, 02156 sub, 02157 TRUE); 02158 } 02159 02160 static int 02161 writer_get_array_len (DBusTypeWriter *writer) 02162 { 02163 _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); 02164 return writer->value_pos - writer->u.array.start_pos; 02165 } 02166 02175 dbus_bool_t 02176 _dbus_type_writer_unrecurse (DBusTypeWriter *writer, 02177 DBusTypeWriter *sub) 02178 { 02179 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */ 02180 _dbus_assert (!writer->type_pos_is_expectation || 02181 (writer->type_pos_is_expectation && sub->type_pos_is_expectation)); 02182 02183 #if RECURSIVE_MARSHAL_WRITE_TRACE 02184 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", 02185 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, 02186 _dbus_type_to_string (writer->container_type)); 02187 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", 02188 sub, sub->type_pos, sub->value_pos, 02189 sub->type_pos_is_expectation, 02190 _dbus_type_to_string (sub->container_type)); 02191 #endif 02192 02193 if (sub->container_type == DBUS_TYPE_STRUCT) 02194 { 02195 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR)) 02196 return FALSE; 02197 } 02198 else if (sub->container_type == DBUS_TYPE_DICT_ENTRY) 02199 { 02200 if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR)) 02201 return FALSE; 02202 } 02203 else if (sub->container_type == DBUS_TYPE_ARRAY) 02204 { 02205 if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */ 02206 { 02207 dbus_uint32_t len; 02208 02209 /* Set the array length */ 02210 len = writer_get_array_len (sub); 02211 _dbus_marshal_set_uint32 (sub->value_str, 02212 sub->u.array.len_pos, 02213 len, 02214 sub->byte_order); 02215 #if RECURSIVE_MARSHAL_WRITE_TRACE 02216 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n", 02217 len, sub->u.array.len_pos); 02218 #endif 02219 } 02220 #if RECURSIVE_MARSHAL_WRITE_TRACE 02221 else 02222 { 02223 _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n"); 02224 } 02225 #endif 02226 } 02227 02228 /* Now get type_pos right for the parent writer. Here are the cases: 02229 * 02230 * Cases !writer->type_pos_is_expectation: 02231 * (in these cases we want to update to the new insertion point) 02232 * 02233 * - if we recursed into a STRUCT then we didn't know in advance 02234 * what the types in the struct would be; so we have to fill in 02235 * that information now. 02236 * writer->type_pos = sub->type_pos 02237 * 02238 * - if we recursed into anything else, we knew the full array 02239 * type, or knew the single typecode marking VARIANT, so 02240 * writer->type_pos is already correct. 02241 * writer->type_pos should remain as-is 02242 * 02243 * - note that the parent is never an ARRAY or VARIANT, if it were 02244 * then type_pos_is_expectation would be TRUE. The parent 02245 * is thus known to be a toplevel or STRUCT. 02246 * 02247 * Cases where writer->type_pos_is_expectation: 02248 * (in these cases we want to update to next expected type to write) 02249 * 02250 * - we recursed from STRUCT into STRUCT and we didn't increment 02251 * type_pos in the parent just to stay consistent with the 02252 * !writer->type_pos_is_expectation case (though we could 02253 * special-case this in recurse_struct instead if we wanted) 02254 * writer->type_pos = sub->type_pos 02255 * 02256 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos 02257 * for parent should have been incremented already 02258 * writer->type_pos should remain as-is 02259 * 02260 * - we recursed from ARRAY into a sub-element, so type_pos in the 02261 * parent is the element type and should remain the element type 02262 * for the benefit of the next child element 02263 * writer->type_pos should remain as-is 02264 * 02265 * - we recursed from VARIANT into its value, so type_pos in the 02266 * parent makes no difference since there's only one value 02267 * and we just finished writing it and won't use type_pos again 02268 * writer->type_pos should remain as-is 02269 * 02270 * 02271 * For all these, DICT_ENTRY is the same as STRUCT 02272 */ 02273 if (writer->type_str != NULL) 02274 { 02275 if ((sub->container_type == DBUS_TYPE_STRUCT || 02276 sub->container_type == DBUS_TYPE_DICT_ENTRY) && 02277 (writer->container_type == DBUS_TYPE_STRUCT || 02278 writer->container_type == DBUS_TYPE_DICT_ENTRY || 02279 writer->container_type == DBUS_TYPE_INVALID)) 02280 { 02281 /* Advance the parent to the next struct field */ 02282 writer->type_pos = sub->type_pos; 02283 } 02284 } 02285 02286 writer->value_pos = sub->value_pos; 02287 02288 #if RECURSIVE_MARSHAL_WRITE_TRACE 02289 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n", 02290 writer, writer->type_pos, writer->value_pos, 02291 writer->type_str ? 02292 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : 02293 "unknown"); 02294 #endif 02295 02296 return TRUE; 02297 } 02298 02307 dbus_bool_t 02308 _dbus_type_writer_write_basic (DBusTypeWriter *writer, 02309 int type, 02310 const void *value) 02311 { 02312 dbus_bool_t retval; 02313 02314 /* First ensure that our type realloc will succeed */ 02315 if (!writer->type_pos_is_expectation && writer->type_str != NULL) 02316 { 02317 if (!_dbus_string_alloc_space (writer->type_str, 1)) 02318 return FALSE; 02319 } 02320 02321 retval = FALSE; 02322 02323 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value)) 02324 goto out; 02325 02326 if (!write_or_verify_typecode (writer, type)) 02327 _dbus_assert_not_reached ("failed to write typecode after prealloc"); 02328 02329 retval = TRUE; 02330 02331 out: 02332 #if RECURSIVE_MARSHAL_WRITE_TRACE 02333 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", 02334 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, 02335 writer->enabled); 02336 #endif 02337 02338 return retval; 02339 } 02340 02355 dbus_bool_t 02356 _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, 02357 int element_type, 02358 const void *value, 02359 int n_elements) 02360 { 02361 _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); 02362 _dbus_assert (dbus_type_is_fixed (element_type)); 02363 _dbus_assert (writer->type_pos_is_expectation); 02364 _dbus_assert (n_elements >= 0); 02365 02366 #if RECURSIVE_MARSHAL_WRITE_TRACE 02367 _dbus_verbose (" type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n", 02368 writer, writer->type_pos, writer->value_pos, n_elements); 02369 #endif 02370 02371 if (!write_or_verify_typecode (writer, element_type)) 02372 _dbus_assert_not_reached ("OOM should not happen if only verifying typecode"); 02373 02374 if (writer->enabled) 02375 { 02376 if (!_dbus_marshal_write_fixed_multi (writer->value_str, 02377 writer->value_pos, 02378 element_type, 02379 value, 02380 n_elements, 02381 writer->byte_order, 02382 &writer->value_pos)) 02383 return FALSE; 02384 } 02385 02386 #if RECURSIVE_MARSHAL_WRITE_TRACE 02387 _dbus_verbose (" type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n", 02388 writer, writer->type_pos, writer->value_pos, n_elements); 02389 #endif 02390 02391 return TRUE; 02392 } 02393 02394 static void 02395 enable_if_after (DBusTypeWriter *writer, 02396 DBusTypeReader *reader, 02397 const DBusTypeReader *start_after) 02398 { 02399 if (start_after) 02400 { 02401 if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after)) 02402 { 02403 _dbus_type_writer_set_enabled (writer, TRUE); 02404 #if RECURSIVE_MARSHAL_WRITE_TRACE 02405 _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n", 02406 writer, writer->value_pos, reader->value_pos, start_after->value_pos); 02407 #endif 02408 } 02409 02410 _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) || 02411 (writer->enabled && _dbus_type_reader_greater_than (reader, start_after))); 02412 } 02413 } 02414 02415 static dbus_bool_t 02416 append_fixup (DBusList **fixups, 02417 const DBusArrayLenFixup *fixup) 02418 { 02419 DBusArrayLenFixup *f; 02420 02421 f = dbus_new (DBusArrayLenFixup, 1); 02422 if (f == NULL) 02423 return FALSE; 02424 02425 *f = *fixup; 02426 02427 if (!_dbus_list_append (fixups, f)) 02428 { 02429 dbus_free (f); 02430 return FALSE; 02431 } 02432 02433 _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader); 02434 _dbus_assert (f->new_len == fixup->new_len); 02435 02436 return TRUE; 02437 } 02438 02439 /* This loop is trivial if you ignore all the start_after nonsense, 02440 * so if you're trying to figure it out, start by ignoring that 02441 */ 02442 static dbus_bool_t 02443 writer_write_reader_helper (DBusTypeWriter *writer, 02444 DBusTypeReader *reader, 02445 const DBusTypeReader *start_after, 02446 int start_after_new_pos, 02447 int start_after_new_len, 02448 DBusList **fixups, 02449 dbus_bool_t inside_start_after) 02450 { 02451 int current_type; 02452 02453 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) 02454 { 02455 if (dbus_type_is_container (current_type)) 02456 { 02457 DBusTypeReader subreader; 02458 DBusTypeWriter subwriter; 02459 const DBusString *sig_str; 02460 int sig_start; 02461 int sig_len; 02462 dbus_bool_t enabled_at_recurse; 02463 dbus_bool_t past_start_after; 02464 int reader_array_len_pos; 02465 int reader_array_start_pos; 02466 dbus_bool_t this_is_start_after; 02467 02468 /* type_pos is checked since e.g. in a struct the struct 02469 * and its first field have the same value_pos. 02470 * type_str will differ in reader/start_after for variants 02471 * where type_str is inside the value_str 02472 */ 02473 if (!inside_start_after && start_after && 02474 reader->value_pos == start_after->value_pos && 02475 reader->type_str == start_after->type_str && 02476 reader->type_pos == start_after->type_pos) 02477 this_is_start_after = TRUE; 02478 else 02479 this_is_start_after = FALSE; 02480 02481 _dbus_type_reader_recurse (reader, &subreader); 02482 02483 if (current_type == DBUS_TYPE_ARRAY) 02484 { 02485 reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader); 02486 reader_array_start_pos = subreader.u.array.start_pos; 02487 } 02488 else 02489 { 02490 /* quiet gcc */ 02491 reader_array_len_pos = -1; 02492 reader_array_start_pos = -1; 02493 } 02494 02495 _dbus_type_reader_get_signature (&subreader, &sig_str, 02496 &sig_start, &sig_len); 02497 02498 #if RECURSIVE_MARSHAL_WRITE_TRACE 02499 _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", 02500 _dbus_type_to_string (current_type), 02501 reader->value_pos, 02502 subreader.value_pos, 02503 writer->value_pos, 02504 start_after ? start_after->value_pos : -1, 02505 _dbus_string_get_length (writer->value_str), 02506 inside_start_after, this_is_start_after); 02507 #endif 02508 02509 if (!inside_start_after && !this_is_start_after) 02510 enable_if_after (writer, &subreader, start_after); 02511 enabled_at_recurse = writer->enabled; 02512 if (!_dbus_type_writer_recurse_contained_len (writer, current_type, 02513 sig_str, sig_start, sig_len, 02514 &subwriter, FALSE)) 02515 goto oom; 02516 02517 #if RECURSIVE_MARSHAL_WRITE_TRACE 02518 _dbus_verbose ("recursed into subwriter at %d write target len %d\n", 02519 subwriter.value_pos, 02520 _dbus_string_get_length (subwriter.value_str)); 02521 #endif 02522 02523 if (!writer_write_reader_helper (&subwriter, &subreader, start_after, 02524 start_after_new_pos, start_after_new_len, 02525 fixups, 02526 inside_start_after || 02527 this_is_start_after)) 02528 goto oom; 02529 02530 #if RECURSIVE_MARSHAL_WRITE_TRACE 02531 _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d write target len %d\n", 02532 _dbus_type_to_string (current_type), 02533 subreader.value_pos, 02534 writer->value_pos, 02535 subwriter.value_pos, 02536 _dbus_string_get_length (writer->value_str)); 02537 #endif 02538 02539 if (!inside_start_after && !this_is_start_after) 02540 enable_if_after (writer, &subreader, start_after); 02541 past_start_after = writer->enabled; 02542 if (!_dbus_type_writer_unrecurse (writer, &subwriter)) 02543 goto oom; 02544 02545 /* If we weren't enabled when we recursed, we didn't 02546 * write an array len; if we passed start_after 02547 * somewhere inside the array, then we need to generate 02548 * a fixup. 02549 */ 02550 if (start_after != NULL && 02551 !enabled_at_recurse && past_start_after && 02552 current_type == DBUS_TYPE_ARRAY && 02553 fixups != NULL) 02554 { 02555 DBusArrayLenFixup fixup; 02556 int bytes_written_after_start_after; 02557 int bytes_before_start_after; 02558 int old_len; 02559 02560 /* this subwriter access is moderately unkosher since we 02561 * already unrecursed, but it works as long as unrecurse 02562 * doesn't break us on purpose 02563 */ 02564 bytes_written_after_start_after = writer_get_array_len (&subwriter); 02565 02566 bytes_before_start_after = 02567 start_after->value_pos - reader_array_start_pos; 02568 02569 fixup.len_pos_in_reader = reader_array_len_pos; 02570 fixup.new_len = 02571 bytes_before_start_after + 02572 start_after_new_len + 02573 bytes_written_after_start_after; 02574 02575 _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) == 02576 (unsigned) fixup.len_pos_in_reader); 02577 02578 old_len = _dbus_unpack_uint32 (reader->byte_order, 02579 _dbus_string_get_const_data_len (reader->value_str, 02580 fixup.len_pos_in_reader, 4)); 02581 02582 if (old_len != fixup.new_len && !append_fixup (fixups, &fixup)) 02583 goto oom; 02584 02585 #if RECURSIVE_MARSHAL_WRITE_TRACE 02586 _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", 02587 fixup.len_pos_in_reader, 02588 fixup.new_len, 02589 reader_array_start_pos, 02590 start_after->value_pos, 02591 bytes_before_start_after, 02592 start_after_new_len, 02593 bytes_written_after_start_after); 02594 #endif 02595 } 02596 } 02597 else 02598 { 02599 DBusBasicValue val; 02600 02601 _dbus_assert (dbus_type_is_basic (current_type)); 02602 02603 #if RECURSIVE_MARSHAL_WRITE_TRACE 02604 _dbus_verbose ("Reading basic value %s at %d\n", 02605 _dbus_type_to_string (current_type), 02606 reader->value_pos); 02607 #endif 02608 02609 _dbus_type_reader_read_basic (reader, &val); 02610 02611 #if RECURSIVE_MARSHAL_WRITE_TRACE 02612 _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n", 02613 _dbus_type_to_string (current_type), 02614 writer->value_pos, 02615 _dbus_string_get_length (writer->value_str), 02616 inside_start_after); 02617 #endif 02618 if (!inside_start_after) 02619 enable_if_after (writer, reader, start_after); 02620 if (!_dbus_type_writer_write_basic (writer, current_type, &val)) 02621 goto oom; 02622 #if RECURSIVE_MARSHAL_WRITE_TRACE 02623 _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n", 02624 _dbus_type_to_string (current_type), 02625 writer->value_pos, 02626 _dbus_string_get_length (writer->value_str)); 02627 #endif 02628 } 02629 02630 _dbus_type_reader_next (reader); 02631 } 02632 02633 return TRUE; 02634 02635 oom: 02636 if (fixups) 02637 apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */ 02638 02639 return FALSE; 02640 } 02641 02642 /* 02643 * Iterate through all values in the given reader, writing a copy of 02644 * each value to the writer. The reader will be moved forward to its 02645 * end position. 02646 * 02647 * If a reader start_after is provided, it should be a reader for the 02648 * same data as the reader to be written. Only values occurring after 02649 * the value pointed to by start_after will be written to the writer. 02650 * 02651 * If start_after is provided, then the copy of the reader will be 02652 * partial. This means that array lengths will not have been copied. 02653 * The assumption is that you wrote a new version of the value at 02654 * start_after to the writer. You have to pass in the start position 02655 * and length of the new value. (If you are deleting the value 02656 * at start_after, pass in 0 for the length.) 02657 * 02658 * If the fixups parameter is non-#NULL, then any array length that 02659 * was read but not written due to start_after will be provided 02660 * as a #DBusArrayLenFixup. The fixup contains the position of the 02661 * array length in the source data, and the correct array length 02662 * assuming you combine the source data before start_after with 02663 * the written data at start_after and beyond. 02664 * 02665 * @param writer the writer to copy to 02666 * @param reader the reader to copy from 02667 * @param start_after #NULL or a reader showing where to start 02668 * @param start_after_new_pos the position of start_after equivalent in the target data 02669 * @param start_after_new_len the length of start_after equivalent in the target data 02670 * @param fixups list to append #DBusArrayLenFixup if the write was partial 02671 * @returns #FALSE if no memory 02672 */ 02673 static dbus_bool_t 02674 _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, 02675 DBusTypeReader *reader, 02676 const DBusTypeReader *start_after, 02677 int start_after_new_pos, 02678 int start_after_new_len, 02679 DBusList **fixups) 02680 { 02681 DBusTypeWriter orig; 02682 int orig_type_len; 02683 int orig_value_len; 02684 int new_bytes; 02685 int orig_enabled; 02686 02687 orig = *writer; 02688 orig_type_len = _dbus_string_get_length (writer->type_str); 02689 orig_value_len = _dbus_string_get_length (writer->value_str); 02690 orig_enabled = writer->enabled; 02691 02692 if (start_after) 02693 _dbus_type_writer_set_enabled (writer, FALSE); 02694 02695 if (!writer_write_reader_helper (writer, reader, start_after, 02696 start_after_new_pos, 02697 start_after_new_len, 02698 fixups, FALSE)) 02699 goto oom; 02700 02701 _dbus_type_writer_set_enabled (writer, orig_enabled); 02702 return TRUE; 02703 02704 oom: 02705 if (!writer->type_pos_is_expectation) 02706 { 02707 new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len; 02708 _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes); 02709 } 02710 new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len; 02711 _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes); 02712 02713 *writer = orig; 02714 02715 return FALSE; 02716 } 02717 02727 dbus_bool_t 02728 _dbus_type_writer_write_reader (DBusTypeWriter *writer, 02729 DBusTypeReader *reader) 02730 { 02731 return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL); 02732 } 02733 02734 /* 02735 * If disabled, a writer can still be iterated forward and recursed/unrecursed 02736 * but won't write any values. Types will still be written unless the 02737 * writer is a "values only" writer, because the writer needs access to 02738 * a valid signature to be able to iterate. 02739 * 02740 * @param writer the type writer 02741 * @param enabled #TRUE if values should be written 02742 */ 02743 static void 02744 _dbus_type_writer_set_enabled (DBusTypeWriter *writer, 02745 dbus_bool_t enabled) 02746 { 02747 writer->enabled = enabled != FALSE; 02748 } 02749 /* end of DBusMarshal group */ 02751 02752 /* tests in dbus-marshal-recursive-util.c */