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