1 /* 2 * Copyright 2005-2012, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 10 #include <Message.h> 11 #include <MessageAdapter.h> 12 #include <MessagePrivate.h> 13 #include <MessageUtils.h> 14 15 #include <DirectMessageTarget.h> 16 #include <MessengerPrivate.h> 17 #include <TokenSpace.h> 18 #include <util/KMessage.h> 19 20 #include <Alignment.h> 21 #include <Application.h> 22 #include <AppMisc.h> 23 #include <BlockCache.h> 24 #include <Entry.h> 25 #include <MessageQueue.h> 26 #include <Messenger.h> 27 #include <Path.h> 28 #include <Point.h> 29 #include <Rect.h> 30 #include <String.h> 31 #include <StringList.h> 32 33 #include <assert.h> 34 #include <ctype.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include "tracing_config.h" 40 // kernel tracing configuration 41 42 //#define VERBOSE_DEBUG_OUTPUT 43 #ifdef VERBOSE_DEBUG_OUTPUT 44 #define DEBUG_FUNCTION_ENTER \ 45 debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \ 46 " data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \ 47 find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \ 48 __LINE__, __PRETTY_FUNCTION__); 49 50 #define DEBUG_FUNCTION_ENTER2 \ 51 debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \ 52 __LINE__, __PRETTY_FUNCTION__); 53 #else 54 #define DEBUG_FUNCTION_ENTER /* nothing */ 55 #define DEBUG_FUNCTION_ENTER2 /* nothing */ 56 #endif 57 58 #if BMESSAGE_TRACING 59 # define KTRACE(format...) ktrace_printf(format) 60 #else 61 # define KTRACE(format...) 62 #endif 63 64 65 const char *B_SPECIFIER_ENTRY = "specifiers"; 66 const char *B_PROPERTY_ENTRY = "property"; 67 const char *B_PROPERTY_NAME_ENTRY = "name"; 68 69 70 static status_t handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout, 71 BMessage *reply); 72 73 extern "C" { 74 // private os function to set the owning team of an area 75 status_t _kern_transfer_area(area_id area, void **_address, 76 uint32 addressSpec, team_id target); 77 } 78 79 80 BBlockCache *BMessage::sMsgCache = NULL; 81 port_id BMessage::sReplyPorts[sNumReplyPorts]; 82 int32 BMessage::sReplyPortInUse[sNumReplyPorts]; 83 84 85 template<typename Type> 86 static void 87 print_to_stream_type(uint8 *pointer) 88 { 89 Type *item = (Type *)pointer; 90 item->PrintToStream(); 91 } 92 93 94 template<typename Type> 95 static void 96 print_type(const char *format, uint8 *pointer) 97 { 98 Type *item = (Type *)pointer; 99 printf(format, *item, *item); 100 } 101 102 103 template<typename Type> 104 static void 105 print_type3(const char *format, uint8 *pointer) 106 { 107 Type *item = (Type *)pointer; 108 printf(format, *item, *item, *item); 109 } 110 111 112 static status_t 113 handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout, 114 BMessage *reply) 115 { 116 DEBUG_FUNCTION_ENTER2; 117 ssize_t size; 118 do { 119 size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout); 120 } while (size == B_INTERRUPTED); 121 122 if (size < 0) 123 return size; 124 125 status_t result; 126 char *buffer = (char *)malloc(size); 127 if (buffer == NULL) 128 return B_NO_MEMORY; 129 130 do { 131 result = read_port(replyPort, _code, buffer, size); 132 } while (result == B_INTERRUPTED); 133 134 if (result < 0 || *_code != kPortMessageCode) { 135 free(buffer); 136 return result < 0 ? result : B_ERROR; 137 } 138 139 result = reply->Unflatten(buffer); 140 free(buffer); 141 return result; 142 } 143 144 145 // #pragma mark - 146 147 148 BMessage::BMessage() 149 { 150 DEBUG_FUNCTION_ENTER; 151 _InitCommon(true); 152 } 153 154 155 BMessage::BMessage(BMessage *other) 156 { 157 DEBUG_FUNCTION_ENTER; 158 _InitCommon(false); 159 *this = *other; 160 } 161 162 163 BMessage::BMessage(uint32 _what) 164 { 165 DEBUG_FUNCTION_ENTER; 166 _InitCommon(true); 167 fHeader->what = what = _what; 168 } 169 170 171 BMessage::BMessage(const BMessage &other) 172 { 173 DEBUG_FUNCTION_ENTER; 174 _InitCommon(false); 175 *this = other; 176 } 177 178 179 BMessage::~BMessage() 180 { 181 DEBUG_FUNCTION_ENTER; 182 _Clear(); 183 } 184 185 186 BMessage & 187 BMessage::operator=(const BMessage &other) 188 { 189 DEBUG_FUNCTION_ENTER; 190 191 if (this == &other) 192 return *this; 193 194 _Clear(); 195 196 fHeader = (message_header *)malloc(sizeof(message_header)); 197 if (fHeader == NULL) 198 return *this; 199 200 if (other.fHeader == NULL) 201 return *this; 202 203 memcpy(fHeader, other.fHeader, sizeof(message_header)); 204 205 // Clear some header flags inherited from the original message that don't 206 // apply to the clone. 207 fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE 208 | MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED 209 | MESSAGE_FLAG_PASS_BY_AREA); 210 // Note, that BeOS R5 seems to keep the reply info. 211 212 if (fHeader->field_count > 0) { 213 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 214 if (other.fFields != NULL) 215 fFields = (field_header *)malloc(fieldsSize); 216 217 if (fFields == NULL) { 218 fHeader->field_count = 0; 219 fHeader->data_size = 0; 220 } else 221 memcpy(fFields, other.fFields, fieldsSize); 222 } 223 224 if (fHeader->data_size > 0) { 225 if (other.fData != NULL) 226 fData = (uint8 *)malloc(fHeader->data_size); 227 228 if (fData == NULL) { 229 fHeader->field_count = 0; 230 free(fFields); 231 fFields = NULL; 232 } else 233 memcpy(fData, other.fData, fHeader->data_size); 234 } 235 236 fHeader->what = what = other.what; 237 fHeader->message_area = -1; 238 fFieldsAvailable = 0; 239 fDataAvailable = 0; 240 241 return *this; 242 } 243 244 245 void * 246 BMessage::operator new(size_t size) 247 { 248 DEBUG_FUNCTION_ENTER2; 249 return sMsgCache->Get(size); 250 } 251 252 253 void * 254 BMessage::operator new(size_t size, const std::nothrow_t &noThrow) 255 { 256 DEBUG_FUNCTION_ENTER2; 257 return sMsgCache->Get(size); 258 } 259 260 261 void * 262 BMessage::operator new(size_t, void *pointer) 263 { 264 DEBUG_FUNCTION_ENTER2; 265 return pointer; 266 } 267 268 269 void 270 BMessage::operator delete(void *pointer, size_t size) 271 { 272 DEBUG_FUNCTION_ENTER2; 273 if (pointer == NULL) 274 return; 275 sMsgCache->Save(pointer, size); 276 } 277 278 279 bool 280 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder, 281 bool deep) const 282 { 283 if (this == &other) 284 return true; 285 286 if (fHeader == NULL) 287 return other.fHeader == NULL; 288 289 if (fHeader->field_count != other.fHeader->field_count) 290 return false; 291 292 for (uint32 i = 0; i < fHeader->field_count; i++) { 293 field_header *field = &fFields[i]; 294 field_header *otherField = NULL; 295 296 const char *name = (const char *)fData + field->offset; 297 if (ignoreFieldOrder) { 298 if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK) 299 return false; 300 } else { 301 otherField = &other.fFields[i]; 302 if (otherField->name_length != field->name_length) 303 return false; 304 305 const char *otherName = (const char *)other.fData 306 + otherField->offset; 307 if (strncmp(name, otherName, field->name_length) != 0) 308 return false; 309 } 310 311 if (otherField->type != field->type 312 || otherField->count != field->count) { 313 return false; 314 } 315 316 uint8 *data = fData + field->offset + field->name_length; 317 uint8 *otherData = other.fData + otherField->offset 318 + otherField->name_length; 319 320 bool needsMemCompare = true; 321 if (deep && field->type == B_MESSAGE_TYPE) { 322 BMessage message, otherMessage; 323 if (message.Unflatten((const char *)data) == B_OK 324 && otherMessage.Unflatten((const char *)otherData) == B_OK) { 325 if (!message.HasSameData(ignoreFieldOrder, deep)) 326 return false; 327 needsMemCompare = false; 328 } 329 } 330 331 if (needsMemCompare) { 332 if (otherField->data_size != field->data_size) 333 return false; 334 if (memcmp(data, otherData, field->data_size) != 0) 335 return false; 336 } 337 } 338 339 return true; 340 } 341 342 343 status_t 344 BMessage::_InitCommon(bool initHeader) 345 { 346 DEBUG_FUNCTION_ENTER; 347 what = 0; 348 349 fHeader = NULL; 350 fFields = NULL; 351 fData = NULL; 352 353 fFieldsAvailable = 0; 354 fDataAvailable = 0; 355 356 fOriginal = NULL; 357 fQueueLink = NULL; 358 359 fArchivingPointer = NULL; 360 361 if (initHeader) 362 return _InitHeader(); 363 364 return B_OK; 365 } 366 367 368 status_t 369 BMessage::_InitHeader() 370 { 371 DEBUG_FUNCTION_ENTER; 372 if (fHeader == NULL) { 373 fHeader = (message_header *)malloc(sizeof(message_header)); 374 if (fHeader == NULL) 375 return B_NO_MEMORY; 376 } 377 378 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table)); 379 380 fHeader->format = MESSAGE_FORMAT_HAIKU; 381 fHeader->flags = MESSAGE_FLAG_VALID; 382 fHeader->what = what; 383 fHeader->current_specifier = -1; 384 fHeader->message_area = -1; 385 386 fHeader->target = B_NULL_TOKEN; 387 fHeader->reply_target = B_NULL_TOKEN; 388 fHeader->reply_port = -1; 389 fHeader->reply_team = -1; 390 391 // initializing the hash table to -1 because 0 is a valid index 392 fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE; 393 memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table)); 394 return B_OK; 395 } 396 397 398 status_t 399 BMessage::_Clear() 400 { 401 DEBUG_FUNCTION_ENTER; 402 if (fHeader != NULL) { 403 // We're going to destroy all information of this message. If there's 404 // still someone waiting for a reply to this message, we have to send 405 // one now. 406 if (IsSourceWaiting()) 407 SendReply(B_NO_REPLY); 408 409 if (fHeader->message_area >= 0) 410 _Dereference(); 411 412 free(fHeader); 413 fHeader = NULL; 414 } 415 416 free(fFields); 417 fFields = NULL; 418 free(fData); 419 fData = NULL; 420 421 fArchivingPointer = NULL; 422 423 fFieldsAvailable = 0; 424 fDataAvailable = 0; 425 426 delete fOriginal; 427 fOriginal = NULL; 428 429 return B_OK; 430 } 431 432 433 status_t 434 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound, 435 type_code *typeFound, int32 *countFound) const 436 { 437 DEBUG_FUNCTION_ENTER; 438 if (fHeader == NULL) 439 return B_NO_INIT; 440 441 if (index < 0 || (uint32)index >= fHeader->field_count) 442 return B_BAD_INDEX; 443 444 if (typeRequested == B_ANY_TYPE) { 445 if (nameFound != NULL) 446 *nameFound = (char *)fData + fFields[index].offset; 447 if (typeFound != NULL) 448 *typeFound = fFields[index].type; 449 if (countFound != NULL) 450 *countFound = fFields[index].count; 451 return B_OK; 452 } 453 454 int32 counter = -1; 455 field_header *field = fFields; 456 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 457 if (field->type == typeRequested) 458 counter++; 459 460 if (counter == index) { 461 if (nameFound != NULL) 462 *nameFound = (char *)fData + field->offset; 463 if (typeFound != NULL) 464 *typeFound = field->type; 465 if (countFound != NULL) 466 *countFound = field->count; 467 return B_OK; 468 } 469 } 470 471 if (counter == -1) 472 return B_BAD_TYPE; 473 474 return B_BAD_INDEX; 475 } 476 477 478 status_t 479 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound) 480 const 481 { 482 DEBUG_FUNCTION_ENTER; 483 if (countFound != NULL) 484 *countFound = 0; 485 486 field_header *field = NULL; 487 status_t result = _FindField(name, B_ANY_TYPE, &field); 488 if (result != B_OK) 489 return result; 490 491 if (typeFound != NULL) 492 *typeFound = field->type; 493 if (countFound != NULL) 494 *countFound = field->count; 495 496 return B_OK; 497 } 498 499 500 status_t 501 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize) 502 const 503 { 504 DEBUG_FUNCTION_ENTER; 505 field_header *field = NULL; 506 status_t result = _FindField(name, B_ANY_TYPE, &field); 507 if (result != B_OK) 508 return result; 509 510 if (typeFound != NULL) 511 *typeFound = field->type; 512 if (fixedSize != NULL) 513 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 514 515 return B_OK; 516 } 517 518 519 status_t 520 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound, 521 bool *fixedSize) const 522 { 523 DEBUG_FUNCTION_ENTER; 524 field_header *field = NULL; 525 status_t result = _FindField(name, B_ANY_TYPE, &field); 526 if (result != B_OK) 527 return result; 528 529 if (typeFound != NULL) 530 *typeFound = field->type; 531 if (countFound != NULL) 532 *countFound = field->count; 533 if (fixedSize != NULL) 534 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 535 536 return B_OK; 537 } 538 539 540 int32 541 BMessage::CountNames(type_code type) const 542 { 543 DEBUG_FUNCTION_ENTER; 544 if (fHeader == NULL) 545 return 0; 546 547 if (type == B_ANY_TYPE) 548 return fHeader->field_count; 549 550 int32 count = 0; 551 field_header *field = fFields; 552 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 553 if (field->type == type) 554 count++; 555 } 556 557 return count; 558 } 559 560 561 bool 562 BMessage::IsEmpty() const 563 { 564 DEBUG_FUNCTION_ENTER; 565 return fHeader == NULL || fHeader->field_count == 0; 566 } 567 568 569 bool 570 BMessage::IsSystem() const 571 { 572 DEBUG_FUNCTION_ENTER; 573 char a = char(what >> 24); 574 char b = char(what >> 16); 575 char c = char(what >> 8); 576 char d = char(what); 577 578 // The BeBook says: 579 // ... we've adopted a strict convention for assigning values to all 580 // Be-defined constants. The value assigned will always be formed by 581 // combining four characters into a multicharacter constant, with the 582 // characters limited to uppercase letters and the underbar 583 // Between that and what's in AppDefs.h, this algo seems like a safe bet: 584 if (a == '_' && isupper(b) && isupper(c) && isupper(d)) 585 return true; 586 587 return false; 588 } 589 590 591 bool 592 BMessage::IsReply() const 593 { 594 DEBUG_FUNCTION_ENTER; 595 return fHeader != NULL && (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0; 596 } 597 598 599 void 600 BMessage::PrintToStream() const 601 { 602 _PrintToStream(""); 603 printf("}\n"); 604 } 605 606 607 void 608 BMessage::_PrintToStream(const char *indent) const 609 { 610 DEBUG_FUNCTION_ENTER; 611 612 int32 value = B_BENDIAN_TO_HOST_INT32(what); 613 printf("BMessage("); 614 if (isprint(*(char *)&value)) 615 printf("'%.4s'", (char *)&value); 616 else 617 printf("0x%" B_PRIx32, what); 618 printf(") {\n"); 619 620 if (fHeader == NULL || fFields == NULL || fData == NULL) 621 return; 622 623 field_header *field = fFields; 624 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 625 value = B_BENDIAN_TO_HOST_INT32(field->type); 626 ssize_t size = 0; 627 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0) 628 size = field->data_size / field->count; 629 630 uint8 *pointer = fData + field->offset + field->name_length; 631 for (uint32 j = 0; j < field->count; j++) { 632 if (field->count == 1) { 633 printf("%s %s = ", indent, 634 (char *)(fData + field->offset)); 635 } else { 636 printf("%s %s[%" B_PRIu32 "] = ", indent, 637 (char *)(fData + field->offset), j); 638 } 639 640 if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) { 641 size = *(uint32 *)pointer; 642 pointer += sizeof(uint32); 643 } 644 645 switch (field->type) { 646 case B_RECT_TYPE: 647 print_to_stream_type<BRect>(pointer); 648 break; 649 650 case B_POINT_TYPE: 651 print_to_stream_type<BPoint>(pointer); 652 break; 653 654 case B_STRING_TYPE: 655 printf("string(\"%.*s\", %ld bytes)\n", (int)size, 656 (char *)pointer, (long)size); 657 break; 658 659 case B_INT8_TYPE: 660 print_type3<int8>("int8(0x%hx or %d or '%c')\n", 661 pointer); 662 break; 663 664 case B_UINT8_TYPE: 665 print_type3<uint8>("uint8(0x%hx or %u or '%c')\n", 666 pointer); 667 break; 668 669 case B_INT16_TYPE: 670 print_type<int16>("int16(0x%x or %d)\n", pointer); 671 break; 672 673 case B_UINT16_TYPE: 674 print_type<uint16>("uint16(0x%x or %u\n", pointer); 675 break; 676 677 case B_INT32_TYPE: 678 print_type<int32>("int32(0x%lx or %ld)\n", pointer); 679 break; 680 681 case B_UINT32_TYPE: 682 print_type<uint32>("uint32(0x%lx or %lu\n", pointer); 683 break; 684 685 case B_INT64_TYPE: 686 print_type<int64>("int64(0x%Lx or %Ld)\n", pointer); 687 break; 688 689 case B_UINT64_TYPE: 690 print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer); 691 break; 692 693 case B_BOOL_TYPE: 694 printf("bool(%s)\n", *((bool *)pointer) != 0 695 ? "true" : "false"); 696 break; 697 698 case B_FLOAT_TYPE: 699 print_type<float>("float(%.4f)\n", pointer); 700 break; 701 702 case B_DOUBLE_TYPE: 703 print_type<double>("double(%.8f)\n", pointer); 704 break; 705 706 case B_REF_TYPE: 707 { 708 entry_ref ref; 709 BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size); 710 711 printf("entry_ref(device=%d, directory=%" B_PRIdINO 712 ", name=\"%s\", ", (int)ref.device, ref.directory, 713 ref.name); 714 715 BPath path(&ref); 716 printf("path=\"%s\")\n", path.Path()); 717 break; 718 } 719 720 case B_MESSAGE_TYPE: 721 { 722 char buffer[1024]; 723 snprintf(buffer, sizeof(buffer), "%s ", indent); 724 725 BMessage message; 726 status_t result = message.Unflatten((const char *)pointer); 727 if (result != B_OK) { 728 printf("failed unflatten: %s\n", strerror(result)); 729 break; 730 } 731 732 message._PrintToStream(buffer); 733 printf("%s }\n", indent); 734 break; 735 } 736 737 default: 738 { 739 printf("(type = '%.4s')(size = %ld)\n", (char *)&value, 740 (long)size); 741 break; 742 } 743 } 744 745 pointer += size; 746 } 747 } 748 } 749 750 751 status_t 752 BMessage::Rename(const char *oldEntry, const char *newEntry) 753 { 754 DEBUG_FUNCTION_ENTER; 755 if (oldEntry == NULL || newEntry == NULL) 756 return B_BAD_VALUE; 757 758 if (fHeader == NULL) 759 return B_NO_INIT; 760 761 if (fHeader->message_area >= 0) 762 _CopyForWrite(); 763 764 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size; 765 int32 *nextField = &fHeader->hash_table[hash]; 766 767 while (*nextField >= 0) { 768 field_header *field = &fFields[*nextField]; 769 770 if (strncmp((const char *)(fData + field->offset), oldEntry, 771 field->name_length) == 0) { 772 // nextField points to the field for oldEntry, save it and unlink 773 int32 index = *nextField; 774 *nextField = field->next_field; 775 field->next_field = -1; 776 777 hash = _HashName(newEntry) % fHeader->hash_table_size; 778 nextField = &fHeader->hash_table[hash]; 779 while (*nextField >= 0) 780 nextField = &fFields[*nextField].next_field; 781 *nextField = index; 782 783 int32 newLength = strlen(newEntry) + 1; 784 status_t result = _ResizeData(field->offset + 1, 785 newLength - field->name_length); 786 if (result != B_OK) 787 return result; 788 789 memcpy(fData + field->offset, newEntry, newLength); 790 field->name_length = newLength; 791 return B_OK; 792 } 793 794 nextField = &field->next_field; 795 } 796 797 return B_NAME_NOT_FOUND; 798 } 799 800 801 bool 802 BMessage::WasDelivered() const 803 { 804 DEBUG_FUNCTION_ENTER; 805 return fHeader != NULL 806 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0; 807 } 808 809 810 bool 811 BMessage::IsSourceWaiting() const 812 { 813 DEBUG_FUNCTION_ENTER; 814 return fHeader != NULL 815 && (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0 816 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0; 817 } 818 819 820 bool 821 BMessage::IsSourceRemote() const 822 { 823 DEBUG_FUNCTION_ENTER; 824 return fHeader != NULL 825 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0 826 && fHeader->reply_team != BPrivate::current_team(); 827 } 828 829 830 BMessenger 831 BMessage::ReturnAddress() const 832 { 833 DEBUG_FUNCTION_ENTER; 834 if (fHeader == NULL || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 835 return BMessenger(); 836 837 BMessenger messenger; 838 BMessenger::Private(messenger).SetTo(fHeader->reply_team, 839 fHeader->reply_port, fHeader->reply_target); 840 return messenger; 841 } 842 843 844 const BMessage * 845 BMessage::Previous() const 846 { 847 DEBUG_FUNCTION_ENTER; 848 /* ToDo: test if the "_previous_" field is used in R5 */ 849 if (fOriginal == NULL) { 850 fOriginal = new BMessage(); 851 852 if (FindMessage("_previous_", fOriginal) != B_OK) { 853 delete fOriginal; 854 fOriginal = NULL; 855 } 856 } 857 858 return fOriginal; 859 } 860 861 862 bool 863 BMessage::WasDropped() const 864 { 865 DEBUG_FUNCTION_ENTER; 866 return fHeader != NULL 867 && (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0; 868 } 869 870 871 BPoint 872 BMessage::DropPoint(BPoint *offset) const 873 { 874 DEBUG_FUNCTION_ENTER; 875 if (offset != NULL) 876 *offset = FindPoint("_drop_offset_"); 877 878 return FindPoint("_drop_point_"); 879 } 880 881 882 status_t 883 BMessage::SendReply(uint32 command, BHandler *replyTo) 884 { 885 DEBUG_FUNCTION_ENTER; 886 BMessage message(command); 887 return SendReply(&message, replyTo); 888 } 889 890 891 status_t 892 BMessage::SendReply(BMessage *reply, BHandler *replyTo, bigtime_t timeout) 893 { 894 DEBUG_FUNCTION_ENTER; 895 BMessenger messenger(replyTo); 896 return SendReply(reply, messenger, timeout); 897 } 898 899 900 status_t 901 BMessage::SendReply(BMessage *reply, BMessenger replyTo, bigtime_t timeout) 902 { 903 DEBUG_FUNCTION_ENTER; 904 if (fHeader == NULL) 905 return B_NO_INIT; 906 907 BMessenger messenger; 908 BMessenger::Private messengerPrivate(messenger); 909 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 910 fHeader->reply_target); 911 912 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 913 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 914 return B_DUPLICATE_REPLY; 915 916 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 917 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 918 status_t result = messenger.SendMessage(reply, replyTo, timeout); 919 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 920 921 if (result != B_OK) { 922 if (set_port_owner(messengerPrivate.Port(), 923 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 924 delete_port(messengerPrivate.Port()); 925 } 926 } 927 928 return result; 929 } 930 931 // no reply required 932 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 933 return B_BAD_REPLY; 934 935 reply->AddMessage("_previous_", this); 936 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 937 status_t result = messenger.SendMessage(reply, replyTo, timeout); 938 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 939 reply->RemoveName("_previous_"); 940 return result; 941 } 942 943 944 status_t 945 BMessage::SendReply(uint32 command, BMessage *replyToReply) 946 { 947 DEBUG_FUNCTION_ENTER; 948 BMessage message(command); 949 return SendReply(&message, replyToReply); 950 } 951 952 953 status_t 954 BMessage::SendReply(BMessage *reply, BMessage *replyToReply, 955 bigtime_t sendTimeout, bigtime_t replyTimeout) 956 { 957 DEBUG_FUNCTION_ENTER; 958 if (fHeader == NULL) 959 return B_NO_INIT; 960 961 BMessenger messenger; 962 BMessenger::Private messengerPrivate(messenger); 963 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 964 fHeader->reply_target); 965 966 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 967 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 968 return B_DUPLICATE_REPLY; 969 970 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 971 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 972 status_t result = messenger.SendMessage(reply, replyToReply, 973 sendTimeout, replyTimeout); 974 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 975 976 if (result != B_OK) { 977 if (set_port_owner(messengerPrivate.Port(), 978 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 979 delete_port(messengerPrivate.Port()); 980 } 981 } 982 983 return result; 984 } 985 986 // no reply required 987 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 988 return B_BAD_REPLY; 989 990 reply->AddMessage("_previous_", this); 991 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 992 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout, 993 replyTimeout); 994 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 995 reply->RemoveName("_previous_"); 996 return result; 997 } 998 999 1000 ssize_t 1001 BMessage::FlattenedSize() const 1002 { 1003 DEBUG_FUNCTION_ENTER; 1004 if (fHeader == NULL) 1005 return B_NO_INIT; 1006 1007 return sizeof(message_header) + fHeader->field_count * sizeof(field_header) 1008 + fHeader->data_size; 1009 } 1010 1011 1012 status_t 1013 BMessage::Flatten(char *buffer, ssize_t size) const 1014 { 1015 DEBUG_FUNCTION_ENTER; 1016 if (buffer == NULL || size < 0) 1017 return B_BAD_VALUE; 1018 1019 if (fHeader == NULL) 1020 return B_NO_INIT; 1021 1022 if (size < FlattenedSize()) 1023 return B_BUFFER_OVERFLOW; 1024 1025 /* we have to sync the what code as it is a public member */ 1026 fHeader->what = what; 1027 1028 memcpy(buffer, fHeader, sizeof(message_header)); 1029 buffer += sizeof(message_header); 1030 1031 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1032 memcpy(buffer, fFields, fieldsSize); 1033 buffer += fieldsSize; 1034 1035 memcpy(buffer, fData, fHeader->data_size); 1036 1037 return B_OK; 1038 } 1039 1040 1041 status_t 1042 BMessage::Flatten(BDataIO *stream, ssize_t *size) const 1043 { 1044 DEBUG_FUNCTION_ENTER; 1045 if (stream == NULL) 1046 return B_BAD_VALUE; 1047 1048 if (fHeader == NULL) 1049 return B_NO_INIT; 1050 1051 /* we have to sync the what code as it is a public member */ 1052 fHeader->what = what; 1053 1054 ssize_t result1 = stream->Write(fHeader, sizeof(message_header)); 1055 if (result1 != sizeof(message_header)) 1056 return result1 < 0 ? result1 : B_ERROR; 1057 1058 ssize_t result2 = 0; 1059 if (fHeader->field_count > 0) { 1060 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1061 result2 = stream->Write(fFields, fieldsSize); 1062 if (result2 != fieldsSize) 1063 return result2 < 0 ? result2 : B_ERROR; 1064 } 1065 1066 ssize_t result3 = 0; 1067 if (fHeader->data_size > 0) { 1068 result3 = stream->Write(fData, fHeader->data_size); 1069 if (result3 != (ssize_t)fHeader->data_size) 1070 return result3 < 0 ? result3 : B_ERROR; 1071 } 1072 1073 if (size) 1074 *size = result1 + result2 + result3; 1075 1076 return B_OK; 1077 } 1078 1079 1080 /* The concept of message sending by area: 1081 1082 The traditional way of sending a message is to send it by flattening it to 1083 a buffer, pushing it through a port, reading it into the outputbuffer and 1084 unflattening it from there (copying the data again). While this works ok 1085 for small messages it does not make any sense for larger ones and may even 1086 hit some port capacity limit. 1087 Often in the life of a BMessage, it will be sent to someone. Almost as 1088 often the one receiving the message will not need to change the message 1089 in any way, but uses it "read only" to get information from it. This means 1090 that all that copying is pretty pointless in the first place since we 1091 could simply pass the original buffers on. 1092 It's obviously not exactly as simple as this, since we cannot just use the 1093 memory of one application in another - but we can share areas with 1094 eachother. 1095 Therefore instead of flattening into a buffer, we copy the message data 1096 into an area, put this information into the message header and only push 1097 this through the port. The receiving looper then builds a BMessage from 1098 the header, that only references the data in the area (not copying it), 1099 allowing read only access to it. 1100 Only if write access is necessary the message will be copyed from the area 1101 to its own buffers (like in the unflatten step before). 1102 The double copying is reduced to a single copy in most cases and we safe 1103 the slower route of moving the data through a port. 1104 Additionally we save us the reference counting with the use of areas that 1105 are reference counted internally. So we don't have to worry about leaving 1106 an area behind or deleting one that is still in use. 1107 */ 1108 1109 status_t 1110 BMessage::_FlattenToArea(message_header **_header) const 1111 { 1112 DEBUG_FUNCTION_ENTER; 1113 if (fHeader == NULL) 1114 return B_NO_INIT; 1115 1116 message_header *header = (message_header *)malloc(sizeof(message_header)); 1117 if (header == NULL) 1118 return B_NO_MEMORY; 1119 1120 memcpy(header, fHeader, sizeof(message_header)); 1121 1122 header->what = what; 1123 header->message_area = -1; 1124 *_header = header; 1125 1126 if (header->field_count == 0 && header->data_size == 0) 1127 return B_OK; 1128 1129 char *address = NULL; 1130 size_t fieldsSize = header->field_count * sizeof(field_header); 1131 size_t size = fieldsSize + header->data_size; 1132 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1); 1133 area_id area = create_area("BMessage data", (void **)&address, 1134 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1135 1136 if (area < 0) { 1137 free(header); 1138 *_header = NULL; 1139 return area; 1140 } 1141 1142 memcpy(address, fFields, fieldsSize); 1143 memcpy(address + fieldsSize, fData, fHeader->data_size); 1144 header->flags |= MESSAGE_FLAG_PASS_BY_AREA; 1145 header->message_area = area; 1146 return B_OK; 1147 } 1148 1149 1150 status_t 1151 BMessage::_Reference() 1152 { 1153 DEBUG_FUNCTION_ENTER; 1154 if (fHeader == NULL) 1155 return B_NO_INIT; 1156 1157 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA; 1158 1159 /* if there is no data at all we don't need the area */ 1160 if (fHeader->field_count == 0 && fHeader->data_size == 0) 1161 return B_OK; 1162 1163 area_info areaInfo; 1164 status_t result = get_area_info(fHeader->message_area, &areaInfo); 1165 if (result != B_OK) 1166 return result; 1167 1168 uint8 *address = (uint8 *)areaInfo.address; 1169 1170 fFields = (field_header *)address; 1171 fData = address + fHeader->field_count * sizeof(field_header); 1172 return B_OK; 1173 } 1174 1175 1176 status_t 1177 BMessage::_Dereference() 1178 { 1179 DEBUG_FUNCTION_ENTER; 1180 if (fHeader == NULL) 1181 return B_NO_INIT; 1182 1183 delete_area(fHeader->message_area); 1184 fHeader->message_area = -1; 1185 fFields = NULL; 1186 fData = NULL; 1187 return B_OK; 1188 } 1189 1190 1191 status_t 1192 BMessage::_CopyForWrite() 1193 { 1194 DEBUG_FUNCTION_ENTER; 1195 if (fHeader == NULL) 1196 return B_NO_INIT; 1197 1198 field_header *newFields = NULL; 1199 uint8 *newData = NULL; 1200 1201 if (fHeader->field_count > 0) { 1202 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1203 newFields = (field_header *)malloc(fieldsSize); 1204 if (newFields == NULL) 1205 return B_NO_MEMORY; 1206 1207 memcpy(newFields, fFields, fieldsSize); 1208 } 1209 1210 if (fHeader->data_size > 0) { 1211 newData = (uint8 *)malloc(fHeader->data_size); 1212 if (newData == NULL) { 1213 free(newFields); 1214 return B_NO_MEMORY; 1215 } 1216 1217 memcpy(newData, fData, fHeader->data_size); 1218 } 1219 1220 _Dereference(); 1221 1222 fFieldsAvailable = 0; 1223 fDataAvailable = 0; 1224 1225 fFields = newFields; 1226 fData = newData; 1227 return B_OK; 1228 } 1229 1230 1231 status_t 1232 BMessage::_ValidateMessage() 1233 { 1234 DEBUG_FUNCTION_ENTER; 1235 if (fHeader == NULL) 1236 return B_NO_INIT; 1237 1238 if (fHeader->field_count == 0) 1239 return B_OK; 1240 1241 if (fFields == NULL) 1242 return B_NO_INIT; 1243 1244 for (uint32 i = 0; i < fHeader->field_count; i++) { 1245 field_header *field = &fFields[i]; 1246 if ((field->next_field >= 0 1247 && (uint32)field->next_field > fHeader->field_count) 1248 || (field->offset + field->name_length + field->data_size 1249 > fHeader->data_size)) { 1250 // the message is corrupt 1251 MakeEmpty(); 1252 return B_BAD_VALUE; 1253 } 1254 } 1255 1256 return B_OK; 1257 } 1258 1259 1260 status_t 1261 BMessage::Unflatten(const char *flatBuffer) 1262 { 1263 DEBUG_FUNCTION_ENTER; 1264 if (flatBuffer == NULL) 1265 return B_BAD_VALUE; 1266 1267 uint32 format = *(uint32 *)flatBuffer; 1268 if (format != MESSAGE_FORMAT_HAIKU) 1269 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer); 1270 1271 // native message unflattening 1272 1273 _Clear(); 1274 1275 fHeader = (message_header *)malloc(sizeof(message_header)); 1276 if (fHeader == NULL) 1277 return B_NO_MEMORY; 1278 1279 memcpy(fHeader, flatBuffer, sizeof(message_header)); 1280 flatBuffer += sizeof(message_header); 1281 1282 if (fHeader->format != MESSAGE_FORMAT_HAIKU 1283 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1284 _InitHeader(); 1285 return B_BAD_VALUE; 1286 } 1287 1288 what = fHeader->what; 1289 1290 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0 1291 && fHeader->message_area >= 0) { 1292 status_t result = _Reference(); 1293 if (result != B_OK) 1294 return result; 1295 } else { 1296 fHeader->message_area = -1; 1297 1298 if (fHeader->field_count > 0) { 1299 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1300 fFields = (field_header *)malloc(fieldsSize); 1301 if (fFields == NULL) { 1302 _InitHeader(); 1303 return B_NO_MEMORY; 1304 } 1305 1306 memcpy(fFields, flatBuffer, fieldsSize); 1307 flatBuffer += fieldsSize; 1308 } 1309 1310 if (fHeader->data_size > 0) { 1311 fData = (uint8 *)malloc(fHeader->data_size); 1312 if (fData == NULL) { 1313 free(fFields); 1314 fFields = NULL; 1315 _InitHeader(); 1316 return B_NO_MEMORY; 1317 } 1318 1319 memcpy(fData, flatBuffer, fHeader->data_size); 1320 } 1321 } 1322 1323 return _ValidateMessage(); 1324 } 1325 1326 1327 status_t 1328 BMessage::Unflatten(BDataIO *stream) 1329 { 1330 DEBUG_FUNCTION_ENTER; 1331 if (stream == NULL) 1332 return B_BAD_VALUE; 1333 1334 uint32 format = 0; 1335 stream->Read(&format, sizeof(uint32)); 1336 if (format != MESSAGE_FORMAT_HAIKU) 1337 return BPrivate::MessageAdapter::Unflatten(format, this, stream); 1338 1339 // native message unflattening 1340 1341 _Clear(); 1342 1343 fHeader = (message_header *)malloc(sizeof(message_header)); 1344 if (fHeader == NULL) 1345 return B_NO_MEMORY; 1346 1347 fHeader->format = format; 1348 uint8 *header = (uint8 *)fHeader; 1349 ssize_t result = stream->Read(header + sizeof(uint32), 1350 sizeof(message_header) - sizeof(uint32)); 1351 if (result != sizeof(message_header) - sizeof(uint32) 1352 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1353 _InitHeader(); 1354 return result < 0 ? result : B_BAD_VALUE; 1355 } 1356 1357 what = fHeader->what; 1358 1359 fHeader->message_area = -1; 1360 1361 if (fHeader->field_count > 0) { 1362 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1363 fFields = (field_header *)malloc(fieldsSize); 1364 if (fFields == NULL) { 1365 _InitHeader(); 1366 return B_NO_MEMORY; 1367 } 1368 1369 result = stream->Read(fFields, fieldsSize); 1370 if (result != fieldsSize) 1371 return result < 0 ? result : B_BAD_VALUE; 1372 } 1373 1374 if (fHeader->data_size > 0) { 1375 fData = (uint8 *)malloc(fHeader->data_size); 1376 if (fData == NULL) { 1377 free(fFields); 1378 fFields = NULL; 1379 _InitHeader(); 1380 return B_NO_MEMORY; 1381 } 1382 1383 result = stream->Read(fData, fHeader->data_size); 1384 if (result != (ssize_t)fHeader->data_size) 1385 return result < 0 ? result : B_BAD_VALUE; 1386 } 1387 1388 return _ValidateMessage(); 1389 } 1390 1391 1392 status_t 1393 BMessage::AddSpecifier(const char *property) 1394 { 1395 DEBUG_FUNCTION_ENTER; 1396 BMessage message(B_DIRECT_SPECIFIER); 1397 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1398 if (result != B_OK) 1399 return result; 1400 1401 return AddSpecifier(&message); 1402 } 1403 1404 1405 status_t 1406 BMessage::AddSpecifier(const char *property, int32 index) 1407 { 1408 DEBUG_FUNCTION_ENTER; 1409 BMessage message(B_INDEX_SPECIFIER); 1410 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1411 if (result != B_OK) 1412 return result; 1413 1414 result = message.AddInt32("index", index); 1415 if (result != B_OK) 1416 return result; 1417 1418 return AddSpecifier(&message); 1419 } 1420 1421 1422 status_t 1423 BMessage::AddSpecifier(const char *property, int32 index, int32 range) 1424 { 1425 DEBUG_FUNCTION_ENTER; 1426 if (range < 0) 1427 return B_BAD_VALUE; 1428 1429 BMessage message(B_RANGE_SPECIFIER); 1430 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1431 if (result != B_OK) 1432 return result; 1433 1434 result = message.AddInt32("index", index); 1435 if (result != B_OK) 1436 return result; 1437 1438 result = message.AddInt32("range", range); 1439 if (result != B_OK) 1440 return result; 1441 1442 return AddSpecifier(&message); 1443 } 1444 1445 1446 status_t 1447 BMessage::AddSpecifier(const char *property, const char *name) 1448 { 1449 DEBUG_FUNCTION_ENTER; 1450 BMessage message(B_NAME_SPECIFIER); 1451 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1452 if (result != B_OK) 1453 return result; 1454 1455 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1456 if (result != B_OK) 1457 return result; 1458 1459 return AddSpecifier(&message); 1460 } 1461 1462 1463 status_t 1464 BMessage::AddSpecifier(const BMessage *specifier) 1465 { 1466 DEBUG_FUNCTION_ENTER; 1467 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1468 if (result != B_OK) 1469 return result; 1470 1471 fHeader->current_specifier++; 1472 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1473 return B_OK; 1474 } 1475 1476 1477 status_t 1478 BMessage::SetCurrentSpecifier(int32 index) 1479 { 1480 DEBUG_FUNCTION_ENTER; 1481 if (index < 0) 1482 return B_BAD_INDEX; 1483 1484 type_code type; 1485 int32 count; 1486 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1487 if (result != B_OK) 1488 return result; 1489 1490 if (index > count) 1491 return B_BAD_INDEX; 1492 1493 fHeader->current_specifier = index; 1494 return B_OK; 1495 } 1496 1497 1498 status_t 1499 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what, 1500 const char **property) const 1501 { 1502 DEBUG_FUNCTION_ENTER; 1503 if (fHeader == NULL) 1504 return B_NO_INIT; 1505 1506 if (index != NULL) 1507 *index = fHeader->current_specifier; 1508 1509 if (fHeader->current_specifier < 0 1510 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1511 return B_BAD_SCRIPT_SYNTAX; 1512 1513 if (specifier) { 1514 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1515 specifier) != B_OK) 1516 return B_BAD_SCRIPT_SYNTAX; 1517 1518 if (_what != NULL) 1519 *_what = specifier->what; 1520 1521 if (property) { 1522 if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK) 1523 return B_BAD_SCRIPT_SYNTAX; 1524 } 1525 } 1526 1527 return B_OK; 1528 } 1529 1530 1531 bool 1532 BMessage::HasSpecifiers() const 1533 { 1534 DEBUG_FUNCTION_ENTER; 1535 return fHeader != NULL 1536 && (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0; 1537 } 1538 1539 1540 status_t 1541 BMessage::PopSpecifier() 1542 { 1543 DEBUG_FUNCTION_ENTER; 1544 if (fHeader == NULL) 1545 return B_NO_INIT; 1546 1547 if (fHeader->current_specifier < 0 || 1548 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1549 return B_BAD_VALUE; 1550 1551 if (fHeader->current_specifier >= 0) 1552 fHeader->current_specifier--; 1553 1554 return B_OK; 1555 } 1556 1557 1558 status_t 1559 BMessage::_ResizeData(uint32 offset, int32 change) 1560 { 1561 if (change == 0) 1562 return B_OK; 1563 1564 /* optimize for the most usual case: appending data */ 1565 if (offset < fHeader->data_size) { 1566 field_header *field = fFields; 1567 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 1568 if (field->offset >= offset) 1569 field->offset += change; 1570 } 1571 } 1572 1573 if (change > 0) { 1574 if (fDataAvailable >= (uint32)change) { 1575 if (offset < fHeader->data_size) { 1576 memmove(fData + offset + change, fData + offset, 1577 fHeader->data_size - offset); 1578 } 1579 1580 fDataAvailable -= change; 1581 fHeader->data_size += change; 1582 return B_OK; 1583 } 1584 1585 size_t size = fHeader->data_size * 2; 1586 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1587 size = max_c(size, fHeader->data_size + change); 1588 1589 uint8 *newData = (uint8 *)realloc(fData, size); 1590 if (size > 0 && newData == NULL) 1591 return B_NO_MEMORY; 1592 1593 fData = newData; 1594 if (offset < fHeader->data_size) { 1595 memmove(fData + offset + change, fData + offset, 1596 fHeader->data_size - offset); 1597 } 1598 1599 fHeader->data_size += change; 1600 fDataAvailable = size - fHeader->data_size; 1601 } else { 1602 ssize_t length = fHeader->data_size - offset + change; 1603 if (length > 0) 1604 memmove(fData + offset, fData + offset - change, length); 1605 1606 // change is negative 1607 fHeader->data_size += change; 1608 fDataAvailable -= change; 1609 1610 if (fDataAvailable > MAX_DATA_PREALLOCATION) { 1611 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1612 ssize_t size = fHeader->data_size + available; 1613 uint8 *newData = (uint8 *)realloc(fData, size); 1614 if (size > 0 && newData == NULL) { 1615 // this is strange, but not really fatal 1616 return B_OK; 1617 } 1618 1619 fData = newData; 1620 fDataAvailable = available; 1621 } 1622 } 1623 1624 return B_OK; 1625 } 1626 1627 1628 uint32 1629 BMessage::_HashName(const char *name) const 1630 { 1631 char ch; 1632 uint32 result = 0; 1633 1634 while ((ch = *name++) != 0) { 1635 result = (result << 7) ^ (result >> 24); 1636 result ^= ch; 1637 } 1638 1639 result ^= result << 12; 1640 return result; 1641 } 1642 1643 1644 status_t 1645 BMessage::_FindField(const char *name, type_code type, field_header **result) 1646 const 1647 { 1648 if (name == NULL) 1649 return B_BAD_VALUE; 1650 1651 if (fHeader == NULL) 1652 return B_NO_INIT; 1653 1654 if (fHeader->field_count == 0 || fFields == NULL || fData == NULL) 1655 return B_NAME_NOT_FOUND; 1656 1657 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1658 int32 nextField = fHeader->hash_table[hash]; 1659 1660 while (nextField >= 0) { 1661 field_header *field = &fFields[nextField]; 1662 if ((field->flags & FIELD_FLAG_VALID) == 0) 1663 break; 1664 1665 if (strncmp((const char *)(fData + field->offset), name, 1666 field->name_length) == 0) { 1667 if (type != B_ANY_TYPE && field->type != type) 1668 return B_BAD_TYPE; 1669 1670 *result = field; 1671 return B_OK; 1672 } 1673 1674 nextField = field->next_field; 1675 } 1676 1677 return B_NAME_NOT_FOUND; 1678 } 1679 1680 1681 status_t 1682 BMessage::_AddField(const char *name, type_code type, bool isFixedSize, 1683 field_header **result) 1684 { 1685 if (fHeader == NULL) 1686 return B_NO_INIT; 1687 1688 if (fFieldsAvailable <= 0) { 1689 uint32 count = fHeader->field_count * 2 + 1; 1690 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1691 1692 field_header *newFields = (field_header *)realloc(fFields, 1693 count * sizeof(field_header)); 1694 if (count > 0 && newFields == NULL) 1695 return B_NO_MEMORY; 1696 1697 fFields = newFields; 1698 fFieldsAvailable = count - fHeader->field_count; 1699 } 1700 1701 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1702 int32 *nextField = &fHeader->hash_table[hash]; 1703 while (*nextField >= 0) 1704 nextField = &fFields[*nextField].next_field; 1705 *nextField = fHeader->field_count; 1706 1707 field_header *field = &fFields[fHeader->field_count]; 1708 field->type = type; 1709 field->count = 0; 1710 field->data_size = 0; 1711 field->next_field = -1; 1712 field->offset = fHeader->data_size; 1713 field->name_length = strlen(name) + 1; 1714 status_t status = _ResizeData(field->offset, field->name_length); 1715 if (status != B_OK) 1716 return status; 1717 1718 memcpy(fData + field->offset, name, field->name_length); 1719 field->flags = FIELD_FLAG_VALID; 1720 if (isFixedSize) 1721 field->flags |= FIELD_FLAG_FIXED_SIZE; 1722 1723 fFieldsAvailable--; 1724 fHeader->field_count++; 1725 *result = field; 1726 return B_OK; 1727 } 1728 1729 1730 status_t 1731 BMessage::_RemoveField(field_header *field) 1732 { 1733 status_t result = _ResizeData(field->offset, -(field->data_size 1734 + field->name_length)); 1735 if (result != B_OK) 1736 return result; 1737 1738 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header); 1739 int32 nextField = field->next_field; 1740 if (nextField > index) 1741 nextField--; 1742 1743 int32 *value = fHeader->hash_table; 1744 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1745 if (*value > index) 1746 *value -= 1; 1747 else if (*value == index) 1748 *value = nextField; 1749 } 1750 1751 field_header *other = fFields; 1752 for (uint32 i = 0; i < fHeader->field_count; i++, other++) { 1753 if (other->next_field > index) 1754 other->next_field--; 1755 else if (other->next_field == index) 1756 other->next_field = nextField; 1757 } 1758 1759 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header); 1760 memmove(fFields + index, fFields + index + 1, size); 1761 fHeader->field_count--; 1762 fFieldsAvailable++; 1763 1764 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) { 1765 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1766 size = (fHeader->field_count + available) * sizeof(field_header); 1767 field_header *newFields = (field_header *)realloc(fFields, size); 1768 if (size > 0 && newFields == NULL) { 1769 // this is strange, but not really fatal 1770 return B_OK; 1771 } 1772 1773 fFields = newFields; 1774 fFieldsAvailable = available; 1775 } 1776 1777 return B_OK; 1778 } 1779 1780 1781 status_t 1782 BMessage::AddData(const char *name, type_code type, const void *data, 1783 ssize_t numBytes, bool isFixedSize, int32 count) 1784 { 1785 // Note that the "count" argument is only a hint at how many items 1786 // the caller expects to add to this field. Since we do no item pre- 1787 // allocation, we ignore this argument. 1788 DEBUG_FUNCTION_ENTER; 1789 if (numBytes <= 0 || data == NULL) 1790 return B_BAD_VALUE; 1791 1792 if (fHeader == NULL) 1793 return B_NO_INIT; 1794 1795 if (fHeader->message_area >= 0) 1796 _CopyForWrite(); 1797 1798 field_header *field = NULL; 1799 status_t result = _FindField(name, type, &field); 1800 if (result == B_NAME_NOT_FOUND) 1801 result = _AddField(name, type, isFixedSize, &field); 1802 1803 if (result != B_OK) 1804 return result; 1805 1806 if (field == NULL) 1807 return B_ERROR; 1808 1809 uint32 offset = field->offset + field->name_length + field->data_size; 1810 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1811 if (field->count) { 1812 ssize_t size = field->data_size / field->count; 1813 if (size != numBytes) 1814 return B_BAD_VALUE; 1815 } 1816 1817 result = _ResizeData(offset, numBytes); 1818 if (result != B_OK) { 1819 if (field->count == 0) 1820 _RemoveField(field); 1821 return result; 1822 } 1823 1824 memcpy(fData + offset, data, numBytes); 1825 field->data_size += numBytes; 1826 } else { 1827 int32 change = numBytes + sizeof(uint32); 1828 result = _ResizeData(offset, change); 1829 if (result != B_OK) { 1830 if (field->count == 0) 1831 _RemoveField(field); 1832 return result; 1833 } 1834 1835 uint32 size = (uint32)numBytes; 1836 memcpy(fData + offset, &size, sizeof(uint32)); 1837 memcpy(fData + offset + sizeof(uint32), data, size); 1838 field->data_size += change; 1839 } 1840 1841 field->count++; 1842 return B_OK; 1843 } 1844 1845 1846 status_t 1847 BMessage::RemoveData(const char *name, int32 index) 1848 { 1849 DEBUG_FUNCTION_ENTER; 1850 if (index < 0) 1851 return B_BAD_INDEX; 1852 1853 if (fHeader == NULL) 1854 return B_NO_INIT; 1855 1856 if (fHeader->message_area >= 0) 1857 _CopyForWrite(); 1858 1859 field_header *field = NULL; 1860 status_t result = _FindField(name, B_ANY_TYPE, &field); 1861 if (result != B_OK) 1862 return result; 1863 1864 if ((uint32)index >= field->count) 1865 return B_BAD_INDEX; 1866 1867 if (field->count == 1) 1868 return _RemoveField(field); 1869 1870 uint32 offset = field->offset + field->name_length; 1871 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1872 ssize_t size = field->data_size / field->count; 1873 result = _ResizeData(offset + index * size, -size); 1874 if (result != B_OK) 1875 return result; 1876 1877 field->data_size -= size; 1878 } else { 1879 uint8 *pointer = fData + offset; 1880 for (int32 i = 0; i < index; i++) { 1881 offset += *(uint32 *)pointer + sizeof(uint32); 1882 pointer = fData + offset; 1883 } 1884 1885 size_t currentSize = *(uint32 *)pointer + sizeof(uint32); 1886 result = _ResizeData(offset, -currentSize); 1887 if (result != B_OK) 1888 return result; 1889 1890 field->data_size -= currentSize; 1891 } 1892 1893 field->count--; 1894 return B_OK; 1895 } 1896 1897 1898 status_t 1899 BMessage::RemoveName(const char *name) 1900 { 1901 DEBUG_FUNCTION_ENTER; 1902 if (fHeader == NULL) 1903 return B_NO_INIT; 1904 1905 if (fHeader->message_area >= 0) 1906 _CopyForWrite(); 1907 1908 field_header *field = NULL; 1909 status_t result = _FindField(name, B_ANY_TYPE, &field); 1910 if (result != B_OK) 1911 return result; 1912 1913 return _RemoveField(field); 1914 } 1915 1916 1917 status_t 1918 BMessage::MakeEmpty() 1919 { 1920 DEBUG_FUNCTION_ENTER; 1921 _Clear(); 1922 return _InitHeader(); 1923 } 1924 1925 1926 status_t 1927 BMessage::FindData(const char *name, type_code type, int32 index, 1928 const void **data, ssize_t *numBytes) const 1929 { 1930 DEBUG_FUNCTION_ENTER; 1931 if (data == NULL) 1932 return B_BAD_VALUE; 1933 1934 *data = NULL; 1935 field_header *field = NULL; 1936 status_t result = _FindField(name, type, &field); 1937 if (result != B_OK) 1938 return result; 1939 1940 if (index < 0 || (uint32)index >= field->count) 1941 return B_BAD_INDEX; 1942 1943 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1944 size_t bytes = field->data_size / field->count; 1945 *data = fData + field->offset + field->name_length + index * bytes; 1946 if (numBytes != NULL) 1947 *numBytes = bytes; 1948 } else { 1949 uint8 *pointer = fData + field->offset + field->name_length; 1950 for (int32 i = 0; i < index; i++) 1951 pointer += *(uint32 *)pointer + sizeof(uint32); 1952 1953 *data = pointer + sizeof(uint32); 1954 if (numBytes != NULL) 1955 *numBytes = *(uint32 *)pointer; 1956 } 1957 1958 return B_OK; 1959 } 1960 1961 1962 status_t 1963 BMessage::ReplaceData(const char *name, type_code type, int32 index, 1964 const void *data, ssize_t numBytes) 1965 { 1966 DEBUG_FUNCTION_ENTER; 1967 if (numBytes <= 0 || data == NULL) 1968 return B_BAD_VALUE; 1969 1970 field_header *field = NULL; 1971 status_t result = _FindField(name, type, &field); 1972 if (result != B_OK) 1973 return result; 1974 1975 if (index < 0 || (uint32)index >= field->count) 1976 return B_BAD_INDEX; 1977 1978 if (fHeader->message_area >= 0) 1979 _CopyForWrite(); 1980 1981 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1982 ssize_t size = field->data_size / field->count; 1983 if (size != numBytes) 1984 return B_BAD_VALUE; 1985 1986 memcpy(fData + field->offset + field->name_length + index * size, data, 1987 size); 1988 } else { 1989 uint32 offset = field->offset + field->name_length; 1990 uint8 *pointer = fData + offset; 1991 1992 for (int32 i = 0; i < index; i++) { 1993 offset += *(uint32 *)pointer + sizeof(uint32); 1994 pointer = fData + offset; 1995 } 1996 1997 size_t currentSize = *(uint32 *)pointer; 1998 int32 change = numBytes - currentSize; 1999 result = _ResizeData(offset, change); 2000 if (result != B_OK) 2001 return result; 2002 2003 uint32 newSize = (uint32)numBytes; 2004 memcpy(fData + offset, &newSize, sizeof(uint32)); 2005 memcpy(fData + offset + sizeof(uint32), data, newSize); 2006 field->data_size += change; 2007 } 2008 2009 return B_OK; 2010 } 2011 2012 2013 bool 2014 BMessage::HasData(const char *name, type_code type, int32 index) const 2015 { 2016 DEBUG_FUNCTION_ENTER; 2017 field_header *field = NULL; 2018 status_t result = _FindField(name, type, &field); 2019 if (result != B_OK) 2020 return false; 2021 2022 if (index < 0 || (uint32)index >= field->count) 2023 return false; 2024 2025 return true; 2026 } 2027 2028 2029 /* Static functions for cache initialization and cleanup */ 2030 void 2031 BMessage::_StaticInit() 2032 { 2033 DEBUG_FUNCTION_ENTER2; 2034 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2035 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2036 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2037 2038 sReplyPortInUse[0] = 0; 2039 sReplyPortInUse[1] = 0; 2040 sReplyPortInUse[2] = 0; 2041 2042 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 2043 } 2044 2045 2046 void 2047 BMessage::_StaticReInitForkedChild() 2048 { 2049 DEBUG_FUNCTION_ENTER2; 2050 2051 // overwrite the inherited ports with a set of our own 2052 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2053 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2054 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2055 2056 sReplyPortInUse[0] = 0; 2057 sReplyPortInUse[1] = 0; 2058 sReplyPortInUse[2] = 0; 2059 } 2060 2061 2062 void 2063 BMessage::_StaticCleanup() 2064 { 2065 DEBUG_FUNCTION_ENTER2; 2066 delete_port(sReplyPorts[0]); 2067 sReplyPorts[0] = -1; 2068 delete_port(sReplyPorts[1]); 2069 sReplyPorts[1] = -1; 2070 delete_port(sReplyPorts[2]); 2071 sReplyPorts[2] = -1; 2072 } 2073 2074 2075 void 2076 BMessage::_StaticCacheCleanup() 2077 { 2078 DEBUG_FUNCTION_ENTER2; 2079 delete sMsgCache; 2080 sMsgCache = NULL; 2081 } 2082 2083 2084 int32 2085 BMessage::_StaticGetCachedReplyPort() 2086 { 2087 DEBUG_FUNCTION_ENTER2; 2088 int index = -1; 2089 for (int32 i = 0; i < sNumReplyPorts; i++) { 2090 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 2091 if (old == 0) { 2092 // This entry is free 2093 index = i; 2094 break; 2095 } else { 2096 // This entry is being used. 2097 atomic_add(&(sReplyPortInUse[i]), -1); 2098 } 2099 } 2100 2101 return index; 2102 } 2103 2104 2105 status_t 2106 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2107 bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const 2108 { 2109 DEBUG_FUNCTION_ENTER; 2110 ssize_t size = 0; 2111 char *buffer = NULL; 2112 message_header *header = NULL; 2113 status_t result = B_OK; 2114 2115 BPrivate::BDirectMessageTarget* direct = NULL; 2116 BMessage *copy = NULL; 2117 if (portOwner == BPrivate::current_team()) 2118 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct); 2119 2120 if (direct != NULL) { 2121 // We have a direct local message target - we can just enqueue the 2122 // message in its message queue. This will also prevent possible 2123 // deadlocks when the queue is full. 2124 copy = new BMessage(*this); 2125 if (copy != NULL) { 2126 header = copy->fHeader; 2127 header->flags = fHeader->flags; 2128 } else { 2129 direct->Release(); 2130 return B_NO_MEMORY; 2131 } 2132 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2133 } else if (fHeader->data_size > B_PAGE_SIZE * 10) { 2134 // ToDo: bind the above size to the max port message size 2135 // use message passing by area for such a large message 2136 result = _FlattenToArea(&header); 2137 if (result != B_OK) 2138 return result; 2139 2140 buffer = (char *)header; 2141 size = sizeof(message_header); 2142 2143 if (header->message_area >= 0) { 2144 team_id target = portOwner; 2145 if (target < 0) { 2146 port_info info; 2147 result = get_port_info(port, &info); 2148 if (result != B_OK) { 2149 free(header); 2150 return result; 2151 } 2152 target = info.team; 2153 } 2154 2155 void *address = NULL; 2156 area_id transfered = _kern_transfer_area(header->message_area, 2157 &address, B_ANY_ADDRESS, target); 2158 if (transfered < 0) { 2159 delete_area(header->message_area); 2160 free(header); 2161 return transfered; 2162 } 2163 2164 header->message_area = transfered; 2165 } 2166 #endif 2167 } else { 2168 size = FlattenedSize(); 2169 buffer = (char *)malloc(size); 2170 if (buffer == NULL) 2171 return B_NO_MEMORY; 2172 2173 result = Flatten(buffer, size); 2174 if (result != B_OK) { 2175 free(buffer); 2176 return result; 2177 } 2178 2179 header = (message_header *)buffer; 2180 } 2181 2182 if (!replyTo.IsValid()) { 2183 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 2184 fHeader->reply_port, fHeader->reply_target); 2185 2186 if (!replyTo.IsValid()) 2187 replyTo = be_app_messenger; 2188 } 2189 2190 BMessenger::Private replyToPrivate(replyTo); 2191 2192 if (replyRequired) { 2193 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 2194 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 2195 } 2196 2197 header->target = token; 2198 header->reply_team = replyToPrivate.Team(); 2199 header->reply_port = replyToPrivate.Port(); 2200 header->reply_target = replyToPrivate.Token(); 2201 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2202 2203 if (direct == NULL) { 2204 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2205 "message: '%c%c%c%c'", portOwner, port, token, 2206 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2207 2208 do { 2209 result = write_port_etc(port, kPortMessageCode, (void *)buffer, 2210 size, B_RELATIVE_TIMEOUT, timeout); 2211 } while (result == B_INTERRUPTED); 2212 } 2213 2214 if (result == B_OK && IsSourceWaiting()) { 2215 // the forwarded message will handle the reply - we must not do 2216 // this anymore 2217 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2218 } 2219 2220 // we need to do this last because it is possible our 2221 // message might be destroyed after it's enqueued in the 2222 // target looper. Thus we don't want to do any ops that depend on 2223 // members of this after the enqueue. 2224 if (direct != NULL) { 2225 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2226 "message: '%c%c%c%c'", port, token, 2227 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2228 2229 // this is a local message transmission 2230 direct->AddMessage(copy); 2231 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2232 // there is currently no message waiting, and we need to wakeup the 2233 // looper 2234 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2235 } 2236 direct->Release(); 2237 } 2238 2239 free(buffer); 2240 return result; 2241 } 2242 2243 2244 /*! 2245 Sends a message and waits synchronously for a reply. 2246 */ 2247 status_t 2248 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2249 BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2250 { 2251 if (IsSourceWaiting()) { 2252 // we can't forward this message synchronously when it's already 2253 // waiting for a reply 2254 return B_ERROR; 2255 } 2256 2257 DEBUG_FUNCTION_ENTER; 2258 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2259 port_id replyPort = B_BAD_PORT_ID; 2260 status_t result = B_OK; 2261 2262 if (cachedReplyPort < 0) { 2263 // All the cached reply ports are in use; create a new one 2264 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2265 if (replyPort < 0) 2266 return replyPort; 2267 } else { 2268 assert(cachedReplyPort < sNumReplyPorts); 2269 replyPort = sReplyPorts[cachedReplyPort]; 2270 } 2271 2272 team_id team = B_BAD_TEAM_ID; 2273 if (be_app != NULL) 2274 team = be_app->Team(); 2275 else { 2276 port_info portInfo; 2277 result = get_port_info(replyPort, &portInfo); 2278 if (result != B_OK) 2279 goto error; 2280 2281 team = portInfo.team; 2282 } 2283 2284 result = set_port_owner(replyPort, portOwner); 2285 if (result != B_OK) 2286 goto error; 2287 2288 // tests if the queue of the reply port is really empty 2289 #if 0 2290 port_info portInfo; 2291 if (get_port_info(replyPort, &portInfo) == B_OK 2292 && portInfo.queue_count > 0) { 2293 debugger("reply port not empty!"); 2294 printf(" reply port not empty! %ld message(s) in queue\n", 2295 portInfo.queue_count); 2296 2297 // fetch and print the messages 2298 for (int32 i = 0; i < portInfo.queue_count; i++) { 2299 char buffer[1024]; 2300 int32 code; 2301 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2302 if (size < 0) { 2303 printf("failed to read message from reply port\n"); 2304 continue; 2305 } 2306 if (size >= (ssize_t)sizeof(buffer)) { 2307 printf("message from reply port too big\n"); 2308 continue; 2309 } 2310 2311 BMemoryIO stream(buffer, size); 2312 BMessage reply; 2313 if (reply.Unflatten(&stream) != B_OK) { 2314 printf("failed to unflatten message from reply port\n"); 2315 continue; 2316 } 2317 2318 printf("message %ld from reply port:\n", i); 2319 reply.PrintToStream(); 2320 } 2321 } 2322 #endif 2323 2324 { 2325 BMessenger replyTarget; 2326 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2327 B_PREFERRED_TOKEN); 2328 // TODO: replying could also use a BDirectMessageTarget like mechanism 2329 // for local targets 2330 result = _SendMessage(port, -1, token, sendTimeout, true, 2331 replyTarget); 2332 } 2333 2334 if (result != B_OK) 2335 goto error; 2336 2337 int32 code; 2338 result = handle_reply(replyPort, &code, replyTimeout, reply); 2339 if (result != B_OK && cachedReplyPort >= 0) { 2340 delete_port(replyPort); 2341 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2342 } 2343 2344 error: 2345 if (cachedReplyPort >= 0) { 2346 // Reclaim ownership of cached port 2347 set_port_owner(replyPort, team); 2348 // Flag as available 2349 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2350 return result; 2351 } 2352 2353 delete_port(replyPort); 2354 return result; 2355 } 2356 2357 2358 status_t 2359 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, 2360 int32 token, bigtime_t timeout) 2361 { 2362 DEBUG_FUNCTION_ENTER2; 2363 if (data == NULL) 2364 return B_BAD_VALUE; 2365 2366 uint32 magic = *(uint32 *)data; 2367 2368 if (magic == MESSAGE_FORMAT_HAIKU 2369 || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2370 message_header *header = (message_header *)data; 2371 header->target = token; 2372 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2373 } else if (magic == MESSAGE_FORMAT_R5) { 2374 uint8 *header = (uint8 *)data; 2375 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2376 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2377 + sizeof(uint8) /* flags */; 2378 *(int32 *)header = token; 2379 } else if (((KMessage::Header *)data)->magic 2380 == KMessage::kMessageHeaderMagic) { 2381 KMessage::Header *header = (KMessage::Header *)data; 2382 header->targetToken = token; 2383 } else { 2384 return B_NOT_A_MESSAGE; 2385 } 2386 2387 // send the message 2388 status_t result; 2389 2390 do { 2391 result = write_port_etc(port, kPortMessageCode, data, size, 2392 B_RELATIVE_TIMEOUT, timeout); 2393 } while (result == B_INTERRUPTED); 2394 2395 return result; 2396 } 2397 2398 2399 void BMessage::_ReservedMessage1() {} 2400 void BMessage::_ReservedMessage2() {} 2401 void BMessage::_ReservedMessage3() {} 2402 2403 2404 // #pragma mark - Macro definitions for data access methods 2405 2406 2407 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2408 2409 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2410 status_t \ 2411 BMessage::Add##typeName(const char *name, type val) \ 2412 { \ 2413 return AddData(name, typeCode, &val, sizeof(type), true); \ 2414 } \ 2415 \ 2416 \ 2417 status_t \ 2418 BMessage::Find##typeName(const char *name, type *p) const \ 2419 { \ 2420 void *ptr = NULL; \ 2421 ssize_t bytes = 0; \ 2422 status_t error = B_OK; \ 2423 \ 2424 *p = type(); \ 2425 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 2426 \ 2427 if (error == B_OK) \ 2428 memcpy(p, ptr, sizeof(type)); \ 2429 \ 2430 return error; \ 2431 } \ 2432 \ 2433 \ 2434 status_t \ 2435 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 2436 { \ 2437 void *ptr = NULL; \ 2438 ssize_t bytes = 0; \ 2439 status_t error = B_OK; \ 2440 \ 2441 *p = type(); \ 2442 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 2443 \ 2444 if (error == B_OK) \ 2445 memcpy(p, ptr, sizeof(type)); \ 2446 \ 2447 return error; \ 2448 } \ 2449 \ 2450 \ 2451 status_t \ 2452 BMessage::Replace##typeName(const char *name, type value) \ 2453 { \ 2454 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \ 2455 } \ 2456 \ 2457 \ 2458 status_t \ 2459 BMessage::Replace##typeName(const char *name, int32 index, type value) \ 2460 { \ 2461 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \ 2462 } \ 2463 \ 2464 \ 2465 bool \ 2466 BMessage::Has##typeName(const char *name, int32 index) const \ 2467 { \ 2468 return HasData(name, typeCode, index); \ 2469 } 2470 2471 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2472 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2473 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2474 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2475 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2476 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2477 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2478 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2479 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2480 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2481 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2482 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2483 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2484 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2485 2486 #undef DEFINE_FUNCTIONS 2487 2488 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2489 bool \ 2490 BMessage::Has##typeName(const char *name, int32 index) const \ 2491 { \ 2492 return HasData(name, typeCode, index); \ 2493 } 2494 2495 2496 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE); 2497 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2498 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2499 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2500 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2501 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2502 2503 #undef DEFINE_HAS_FUNCTION 2504 2505 2506 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2507 type \ 2508 BMessage::Find##typeName(const char *name, int32 index) const \ 2509 { \ 2510 type val = initialize; \ 2511 Find##typeName(name, index, &val); \ 2512 return val; \ 2513 } 2514 2515 2516 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2517 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2518 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 2519 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2520 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2521 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2522 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2523 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2524 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2525 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2526 2527 #undef DEFINE_LAZY_FIND_FUNCTION 2528 2529 2530 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \ 2531 type \ 2532 BMessage::Get##typeName(const char *name, type defaultValue) const \ 2533 { \ 2534 return Get##typeName(name, 0, defaultValue); \ 2535 } \ 2536 \ 2537 \ 2538 type \ 2539 BMessage::Get##typeName(const char *name, int32 index, \ 2540 type defaultValue) const \ 2541 { \ 2542 type value; \ 2543 if (Find##typeName(name, index, &value) == B_OK) \ 2544 return value; \ 2545 \ 2546 return defaultValue; \ 2547 } \ 2548 \ 2549 \ 2550 status_t \ 2551 BMessage::Set##typeName(const char *name, type value) \ 2552 { \ 2553 return SetData(name, typeCode, &value, sizeof(type)); \ 2554 } \ 2555 2556 2557 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2558 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2559 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2560 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2561 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2562 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2563 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2564 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2565 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2566 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2567 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2568 2569 #undef DEFINE_SET_GET_FUNCTION 2570 2571 2572 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \ 2573 type \ 2574 BMessage::Get##typeName(const char *name, const type& defaultValue) const \ 2575 { \ 2576 return Get##typeName(name, 0, defaultValue); \ 2577 } \ 2578 \ 2579 \ 2580 type \ 2581 BMessage::Get##typeName(const char *name, int32 index, \ 2582 const type& defaultValue) const \ 2583 { \ 2584 type value; \ 2585 if (Find##typeName(name, index, &value) == B_OK) \ 2586 return value; \ 2587 \ 2588 return defaultValue; \ 2589 } \ 2590 \ 2591 \ 2592 status_t \ 2593 BMessage::Set##typeName(const char *name, const type& value) \ 2594 { \ 2595 return SetData(name, typeCode, &value, sizeof(type)); \ 2596 } \ 2597 2598 2599 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2600 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2601 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2602 2603 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS 2604 2605 2606 status_t 2607 BMessage::AddAlignment(const char *name, const BAlignment &alignment) 2608 { 2609 int32 data[2] = { alignment.horizontal, alignment.vertical }; 2610 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data)); 2611 } 2612 2613 2614 status_t 2615 BMessage::AddString(const char *name, const char *string) 2616 { 2617 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, 2618 false); 2619 } 2620 2621 2622 status_t 2623 BMessage::AddString(const char *name, const BString &string) 2624 { 2625 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, 2626 false); 2627 } 2628 2629 2630 status_t 2631 BMessage::AddStrings(const char *name, const BStringList &list) 2632 { 2633 int32 count = list.CountStrings(); 2634 for (int32 i = 0; i < count; i++) { 2635 status_t error = AddString(name, list.StringAt(i)); 2636 if (error != B_OK) 2637 return error; 2638 } 2639 2640 return B_OK; 2641 } 2642 2643 2644 status_t 2645 BMessage::AddPointer(const char *name, const void *pointer) 2646 { 2647 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2648 } 2649 2650 2651 status_t 2652 BMessage::AddMessenger(const char *name, BMessenger messenger) 2653 { 2654 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2655 } 2656 2657 2658 status_t 2659 BMessage::AddRef(const char *name, const entry_ref *ref) 2660 { 2661 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2662 char buffer[size]; 2663 2664 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2665 2666 if (error >= B_OK) 2667 error = AddData(name, B_REF_TYPE, buffer, size, false); 2668 2669 return error; 2670 } 2671 2672 2673 status_t 2674 BMessage::AddMessage(const char *name, const BMessage *message) 2675 { 2676 if (message == NULL) 2677 return B_BAD_VALUE; 2678 2679 // TODO: This and the following functions waste time by allocating and 2680 // copying an extra buffer. Functions can be added that return a direct 2681 // pointer into the message. 2682 2683 char stackBuffer[16384]; 2684 ssize_t size = message->FlattenedSize(); 2685 2686 char *buffer; 2687 if (size > (ssize_t)sizeof(stackBuffer)) { 2688 buffer = (char *)malloc(size); 2689 if (buffer == NULL) 2690 return B_NO_MEMORY; 2691 } else 2692 buffer = stackBuffer; 2693 2694 status_t error = message->Flatten(buffer, size); 2695 2696 if (error >= B_OK) 2697 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2698 2699 if (buffer != stackBuffer) 2700 free(buffer); 2701 2702 return error; 2703 } 2704 2705 2706 status_t 2707 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 2708 { 2709 if (object == NULL) 2710 return B_BAD_VALUE; 2711 2712 char stackBuffer[16384]; 2713 ssize_t size = object->FlattenedSize(); 2714 2715 char *buffer; 2716 if (size > (ssize_t)sizeof(stackBuffer)) { 2717 buffer = (char *)malloc(size); 2718 if (buffer == NULL) 2719 return B_NO_MEMORY; 2720 } else 2721 buffer = stackBuffer; 2722 2723 status_t error = object->Flatten(buffer, size); 2724 2725 if (error >= B_OK) 2726 error = AddData(name, object->TypeCode(), buffer, size, false); 2727 2728 if (buffer != stackBuffer) 2729 free(buffer); 2730 2731 return error; 2732 } 2733 2734 2735 status_t 2736 BMessage::Append(const BMessage &other) 2737 { 2738 field_header *field = other.fFields; 2739 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) { 2740 const char *name = (const char *)(other.fData + field->offset); 2741 const void *data = (const void *)(other.fData + field->offset 2742 + field->name_length); 2743 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 2744 size_t size = field->data_size / field->count; 2745 2746 for (uint32 j = 0; j < field->count; j++) { 2747 if (!isFixed) { 2748 size = *(uint32 *)data; 2749 data = (const void *)((const char *)data + sizeof(uint32)); 2750 } 2751 2752 status_t status = AddData(name, field->type, data, size, 2753 isFixed, 1); 2754 if (status != B_OK) 2755 return status; 2756 2757 data = (const void *)((const char *)data + size); 2758 } 2759 } 2760 return B_OK; 2761 } 2762 2763 2764 status_t 2765 BMessage::FindAlignment(const char *name, BAlignment *alignment) const 2766 { 2767 return FindAlignment(name, 0, alignment); 2768 } 2769 2770 2771 status_t 2772 BMessage::FindAlignment(const char *name, int32 index, BAlignment *alignment) 2773 const 2774 { 2775 if (!alignment) 2776 return B_BAD_VALUE; 2777 2778 int32 *data; 2779 ssize_t bytes; 2780 2781 status_t err = FindData(name, B_ALIGNMENT_TYPE, index, 2782 (const void**)&data, &bytes); 2783 2784 if (err == B_OK) { 2785 if (bytes != sizeof(int32[2])) 2786 return B_ERROR; 2787 2788 alignment->horizontal = (enum alignment)(*data); 2789 alignment->vertical = (vertical_alignment)*(data + 1); 2790 } 2791 2792 return err; 2793 } 2794 2795 2796 status_t 2797 BMessage::FindString(const char *name, const char **string) const 2798 { 2799 return FindString(name, 0, string); 2800 } 2801 2802 2803 status_t 2804 BMessage::FindString(const char *name, int32 index, const char **string) const 2805 { 2806 ssize_t bytes; 2807 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 2808 } 2809 2810 2811 status_t 2812 BMessage::FindString(const char *name, BString *string) const 2813 { 2814 return FindString(name, 0, string); 2815 } 2816 2817 2818 status_t 2819 BMessage::FindString(const char *name, int32 index, BString *string) const 2820 { 2821 if (string == NULL) 2822 return B_BAD_VALUE; 2823 2824 const char *value; 2825 status_t error = FindString(name, index, &value); 2826 2827 // Find*() clobbers the object even on failure 2828 string->SetTo(value); 2829 return error; 2830 } 2831 2832 2833 status_t 2834 BMessage::FindStrings(const char *name, BStringList *list) const 2835 { 2836 if (list == NULL) 2837 return B_BAD_VALUE; 2838 2839 list->MakeEmpty(); 2840 2841 // get the number of items 2842 type_code type; 2843 int32 count; 2844 if (GetInfo(name, &type, &count) != B_OK) 2845 return B_NAME_NOT_FOUND; 2846 2847 if (type != B_STRING_TYPE) 2848 return B_BAD_DATA; 2849 2850 for (int32 i = 0; i < count; i++) { 2851 BString string; 2852 status_t error = FindString(name, i, &string); 2853 if (error != B_OK) 2854 return error; 2855 if (!list->Add(string)) 2856 return B_NO_MEMORY; 2857 } 2858 2859 return B_OK; 2860 } 2861 2862 2863 status_t 2864 BMessage::FindPointer(const char *name, void **pointer) const 2865 { 2866 return FindPointer(name, 0, pointer); 2867 } 2868 2869 2870 status_t 2871 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 2872 { 2873 if (pointer == NULL) 2874 return B_BAD_VALUE; 2875 2876 void **data = NULL; 2877 ssize_t size = 0; 2878 status_t error = FindData(name, B_POINTER_TYPE, index, 2879 (const void **)&data, &size); 2880 2881 if (error == B_OK) 2882 *pointer = *data; 2883 else 2884 *pointer = NULL; 2885 2886 return error; 2887 } 2888 2889 2890 status_t 2891 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 2892 { 2893 return FindMessenger(name, 0, messenger); 2894 } 2895 2896 2897 status_t 2898 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 2899 const 2900 { 2901 if (messenger == NULL) 2902 return B_BAD_VALUE; 2903 2904 void *data = NULL; 2905 ssize_t size = 0; 2906 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2907 (const void **)&data, &size); 2908 2909 if (error == B_OK) 2910 memcpy(messenger, data, sizeof(BMessenger)); 2911 else 2912 *messenger = BMessenger(); 2913 2914 return error; 2915 } 2916 2917 2918 status_t 2919 BMessage::FindRef(const char *name, entry_ref *ref) const 2920 { 2921 return FindRef(name, 0, ref); 2922 } 2923 2924 2925 status_t 2926 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 2927 { 2928 if (ref == NULL) 2929 return B_BAD_VALUE; 2930 2931 void *data = NULL; 2932 ssize_t size = 0; 2933 status_t error = FindData(name, B_REF_TYPE, index, 2934 (const void **)&data, &size); 2935 2936 if (error == B_OK) 2937 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 2938 else 2939 *ref = entry_ref(); 2940 2941 return error; 2942 } 2943 2944 2945 status_t 2946 BMessage::FindMessage(const char *name, BMessage *message) const 2947 { 2948 return FindMessage(name, 0, message); 2949 } 2950 2951 2952 status_t 2953 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 2954 { 2955 if (message == NULL) 2956 return B_BAD_VALUE; 2957 2958 void *data = NULL; 2959 ssize_t size = 0; 2960 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2961 (const void **)&data, &size); 2962 2963 if (error == B_OK) 2964 error = message->Unflatten((const char *)data); 2965 else 2966 *message = BMessage(); 2967 2968 return error; 2969 } 2970 2971 2972 status_t 2973 BMessage::FindFlat(const char *name, BFlattenable *object) const 2974 { 2975 return FindFlat(name, 0, object); 2976 } 2977 2978 2979 status_t 2980 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 2981 { 2982 if (object == NULL) 2983 return B_BAD_VALUE; 2984 2985 void *data = NULL; 2986 ssize_t numBytes = 0; 2987 status_t error = FindData(name, object->TypeCode(), index, 2988 (const void **)&data, &numBytes); 2989 2990 if (error == B_OK) 2991 error = object->Unflatten(object->TypeCode(), data, numBytes); 2992 2993 return error; 2994 } 2995 2996 2997 status_t 2998 BMessage::FindData(const char *name, type_code type, const void **data, 2999 ssize_t *numBytes) const 3000 { 3001 return FindData(name, type, 0, data, numBytes); 3002 } 3003 3004 3005 status_t 3006 BMessage::ReplaceAlignment(const char *name, const BAlignment &alignment) 3007 { 3008 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3009 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data)); 3010 } 3011 3012 3013 status_t 3014 BMessage::ReplaceAlignment(const char *name, int32 index, 3015 const BAlignment &alignment) 3016 { 3017 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3018 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data)); 3019 } 3020 3021 3022 status_t 3023 BMessage::ReplaceString(const char *name, const char *string) 3024 { 3025 if (string == NULL) 3026 return B_BAD_VALUE; 3027 3028 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 3029 } 3030 3031 3032 status_t 3033 BMessage::ReplaceString(const char *name, int32 index, const char *string) 3034 { 3035 if (string == NULL) 3036 return B_BAD_VALUE; 3037 3038 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 3039 } 3040 3041 3042 status_t 3043 BMessage::ReplaceString(const char *name, const BString &string) 3044 { 3045 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 3046 string.Length() + 1); 3047 } 3048 3049 3050 status_t 3051 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 3052 { 3053 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 3054 string.Length() + 1); 3055 } 3056 3057 3058 status_t 3059 BMessage::ReplacePointer(const char *name, const void *pointer) 3060 { 3061 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 3062 } 3063 3064 3065 status_t 3066 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 3067 { 3068 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 3069 } 3070 3071 3072 status_t 3073 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 3074 { 3075 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 3076 sizeof(BMessenger)); 3077 } 3078 3079 3080 status_t 3081 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 3082 { 3083 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 3084 sizeof(BMessenger)); 3085 } 3086 3087 3088 status_t 3089 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 3090 { 3091 return ReplaceRef(name, 0, ref); 3092 } 3093 3094 3095 status_t 3096 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 3097 { 3098 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 3099 char buffer[size]; 3100 3101 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 3102 3103 if (error >= B_OK) 3104 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 3105 3106 return error; 3107 } 3108 3109 3110 status_t 3111 BMessage::ReplaceMessage(const char *name, const BMessage *message) 3112 { 3113 return ReplaceMessage(name, 0, message); 3114 } 3115 3116 3117 status_t 3118 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 3119 { 3120 if (message == NULL) 3121 return B_BAD_VALUE; 3122 3123 ssize_t size = message->FlattenedSize(); 3124 char buffer[size]; 3125 3126 status_t error = message->Flatten(buffer, size); 3127 3128 if (error >= B_OK) 3129 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 3130 3131 return error; 3132 } 3133 3134 3135 status_t 3136 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 3137 { 3138 return ReplaceFlat(name, 0, object); 3139 } 3140 3141 3142 status_t 3143 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 3144 { 3145 if (object == NULL) 3146 return B_BAD_VALUE; 3147 3148 ssize_t size = object->FlattenedSize(); 3149 char buffer[size]; 3150 3151 status_t error = object->Flatten(buffer, size); 3152 3153 if (error >= B_OK) 3154 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 3155 3156 return error; 3157 } 3158 3159 3160 status_t 3161 BMessage::ReplaceData(const char *name, type_code type, const void *data, 3162 ssize_t numBytes) 3163 { 3164 return ReplaceData(name, type, 0, data, numBytes); 3165 } 3166 3167 3168 bool 3169 BMessage::HasFlat(const char *name, const BFlattenable *object) const 3170 { 3171 return HasFlat(name, 0, object); 3172 } 3173 3174 3175 bool 3176 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 3177 const 3178 { 3179 return HasData(name, object->TypeCode(), index); 3180 } 3181 3182 3183 const char* 3184 BMessage::GetString(const char *name, const char *defaultValue) const 3185 { 3186 return GetString(name, 0, defaultValue); 3187 } 3188 3189 3190 const char* 3191 BMessage::GetString(const char *name, int32 index, 3192 const char *defaultValue) const 3193 { 3194 const char* value; 3195 if (FindString(name, index, &value) == B_OK) 3196 return value; 3197 3198 return defaultValue; 3199 } 3200 3201 3202 status_t 3203 BMessage::SetString(const char *name, const BString& value) 3204 { 3205 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1); 3206 } 3207 3208 3209 status_t 3210 BMessage::SetString(const char *name, const char* value) 3211 { 3212 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1); 3213 } 3214 3215 3216 status_t 3217 BMessage::SetData(const char* name, type_code type, const void* data, 3218 ssize_t numBytes) 3219 { 3220 if (numBytes <= 0 || data == NULL) 3221 return B_BAD_VALUE; 3222 3223 if (ReplaceData(name, type, data, numBytes) == B_OK) 3224 return B_OK; 3225 3226 return AddData(name, type, data, numBytes); 3227 } 3228