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