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