1 /* 2 * Copyright 2005-2014 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 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 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 917 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 918 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 919 return B_DUPLICATE_REPLY; 920 921 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 922 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 923 status_t result = messenger.SendMessage(reply, replyTo, timeout); 924 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 925 926 if (result != B_OK) { 927 if (set_port_owner(messengerPrivate.Port(), 928 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 929 delete_port(messengerPrivate.Port()); 930 } 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 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout, 998 replyTimeout); 999 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 1000 reply->RemoveName("_previous_"); 1001 return result; 1002 } 1003 1004 1005 ssize_t 1006 BMessage::FlattenedSize() const 1007 { 1008 DEBUG_FUNCTION_ENTER; 1009 if (fHeader == NULL) 1010 return B_NO_INIT; 1011 1012 return sizeof(message_header) + fHeader->field_count * sizeof(field_header) 1013 + fHeader->data_size; 1014 } 1015 1016 1017 status_t 1018 BMessage::Flatten(char* buffer, ssize_t size) const 1019 { 1020 DEBUG_FUNCTION_ENTER; 1021 if (buffer == NULL || size < 0) 1022 return B_BAD_VALUE; 1023 1024 if (fHeader == NULL) 1025 return B_NO_INIT; 1026 1027 if (size < FlattenedSize()) 1028 return B_BUFFER_OVERFLOW; 1029 1030 /* we have to sync the what code as it is a public member */ 1031 fHeader->what = what; 1032 1033 memcpy(buffer, fHeader, sizeof(message_header)); 1034 buffer += sizeof(message_header); 1035 1036 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1037 memcpy(buffer, fFields, fieldsSize); 1038 buffer += fieldsSize; 1039 1040 memcpy(buffer, fData, fHeader->data_size); 1041 1042 return B_OK; 1043 } 1044 1045 1046 status_t 1047 BMessage::Flatten(BDataIO* stream, ssize_t* size) const 1048 { 1049 DEBUG_FUNCTION_ENTER; 1050 if (stream == NULL) 1051 return B_BAD_VALUE; 1052 1053 if (fHeader == NULL) 1054 return B_NO_INIT; 1055 1056 /* we have to sync the what code as it is a public member */ 1057 fHeader->what = what; 1058 1059 ssize_t result1 = stream->Write(fHeader, sizeof(message_header)); 1060 if (result1 != sizeof(message_header)) 1061 return result1 < 0 ? result1 : B_ERROR; 1062 1063 ssize_t result2 = 0; 1064 if (fHeader->field_count > 0) { 1065 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1066 result2 = stream->Write(fFields, fieldsSize); 1067 if (result2 != fieldsSize) 1068 return result2 < 0 ? result2 : B_ERROR; 1069 } 1070 1071 ssize_t result3 = 0; 1072 if (fHeader->data_size > 0) { 1073 result3 = stream->Write(fData, fHeader->data_size); 1074 if (result3 != (ssize_t)fHeader->data_size) 1075 return result3 < 0 ? result3 : B_ERROR; 1076 } 1077 1078 if (size) 1079 *size = result1 + result2 + result3; 1080 1081 return B_OK; 1082 } 1083 1084 1085 /* The concept of message sending by area: 1086 1087 The traditional way of sending a message is to send it by flattening it to 1088 a buffer, pushing it through a port, reading it into the outputbuffer and 1089 unflattening it from there (copying the data again). While this works ok 1090 for small messages it does not make any sense for larger ones and may even 1091 hit some port capacity limit. 1092 Often in the life of a BMessage, it will be sent to someone. Almost as 1093 often the one receiving the message will not need to change the message 1094 in any way, but uses it "read only" to get information from it. This means 1095 that all that copying is pretty pointless in the first place since we 1096 could simply pass the original buffers on. 1097 It's obviously not exactly as simple as this, since we cannot just use the 1098 memory of one application in another - but we can share areas with 1099 eachother. 1100 Therefore instead of flattening into a buffer, we copy the message data 1101 into an area, put this information into the message header and only push 1102 this through the port. The receiving looper then builds a BMessage from 1103 the header, that only references the data in the area (not copying it), 1104 allowing read only access to it. 1105 Only if write access is necessary the message will be copyed from the area 1106 to its own buffers (like in the unflatten step before). 1107 The double copying is reduced to a single copy in most cases and we safe 1108 the slower route of moving the data through a port. 1109 Additionally we save us the reference counting with the use of areas that 1110 are reference counted internally. So we don't have to worry about leaving 1111 an area behind or deleting one that is still in use. 1112 */ 1113 1114 status_t 1115 BMessage::_FlattenToArea(message_header** _header) const 1116 { 1117 DEBUG_FUNCTION_ENTER; 1118 if (fHeader == NULL) 1119 return B_NO_INIT; 1120 1121 message_header* header = (message_header*)malloc(sizeof(message_header)); 1122 if (header == NULL) 1123 return B_NO_MEMORY; 1124 1125 memcpy(header, fHeader, sizeof(message_header)); 1126 1127 header->what = what; 1128 header->message_area = -1; 1129 *_header = header; 1130 1131 if (header->field_count == 0 && header->data_size == 0) 1132 return B_OK; 1133 1134 char* address = NULL; 1135 size_t fieldsSize = header->field_count * sizeof(field_header); 1136 size_t size = fieldsSize + header->data_size; 1137 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1); 1138 area_id area = create_area("BMessage data", (void**)&address, 1139 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1140 1141 if (area < 0) { 1142 free(header); 1143 *_header = NULL; 1144 return area; 1145 } 1146 1147 memcpy(address, fFields, fieldsSize); 1148 memcpy(address + fieldsSize, fData, fHeader->data_size); 1149 header->flags |= MESSAGE_FLAG_PASS_BY_AREA; 1150 header->message_area = area; 1151 return B_OK; 1152 } 1153 1154 1155 status_t 1156 BMessage::_Reference() 1157 { 1158 DEBUG_FUNCTION_ENTER; 1159 if (fHeader == NULL) 1160 return B_NO_INIT; 1161 1162 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA; 1163 1164 /* if there is no data at all we don't need the area */ 1165 if (fHeader->field_count == 0 && fHeader->data_size == 0) 1166 return B_OK; 1167 1168 area_info areaInfo; 1169 status_t result = get_area_info(fHeader->message_area, &areaInfo); 1170 if (result != B_OK) 1171 return result; 1172 1173 if (areaInfo.team != BPrivate::current_team()) 1174 return B_BAD_VALUE; 1175 1176 set_area_protection(fHeader->message_area, B_READ_AREA); 1177 1178 uint8* address = (uint8*)areaInfo.address; 1179 1180 fFields = (field_header*)address; 1181 fData = address + fHeader->field_count * sizeof(field_header); 1182 return B_OK; 1183 } 1184 1185 1186 status_t 1187 BMessage::_Dereference() 1188 { 1189 DEBUG_FUNCTION_ENTER; 1190 if (fHeader == NULL) 1191 return B_NO_INIT; 1192 1193 delete_area(fHeader->message_area); 1194 fHeader->message_area = -1; 1195 fFields = NULL; 1196 fData = NULL; 1197 return B_OK; 1198 } 1199 1200 1201 status_t 1202 BMessage::_CopyForWrite() 1203 { 1204 DEBUG_FUNCTION_ENTER; 1205 if (fHeader == NULL) 1206 return B_NO_INIT; 1207 1208 field_header* newFields = NULL; 1209 uint8* newData = NULL; 1210 1211 if (fHeader->field_count > 0) { 1212 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1213 newFields = (field_header*)malloc(fieldsSize); 1214 if (newFields == NULL) 1215 return B_NO_MEMORY; 1216 1217 memcpy(newFields, fFields, fieldsSize); 1218 } 1219 1220 if (fHeader->data_size > 0) { 1221 newData = (uint8*)malloc(fHeader->data_size); 1222 if (newData == NULL) { 1223 free(newFields); 1224 return B_NO_MEMORY; 1225 } 1226 1227 memcpy(newData, fData, fHeader->data_size); 1228 } 1229 1230 _Dereference(); 1231 1232 fFieldsAvailable = 0; 1233 fDataAvailable = 0; 1234 1235 fFields = newFields; 1236 fData = newData; 1237 return B_OK; 1238 } 1239 1240 1241 status_t 1242 BMessage::_ValidateMessage() 1243 { 1244 DEBUG_FUNCTION_ENTER; 1245 if (fHeader == NULL) 1246 return B_NO_INIT; 1247 1248 if (fHeader->field_count == 0) 1249 return B_OK; 1250 1251 if (fFields == NULL) 1252 return B_NO_INIT; 1253 1254 for (uint32 i = 0; i < fHeader->field_count; i++) { 1255 field_header* field = &fFields[i]; 1256 if ((field->next_field >= 0 1257 && (uint32)field->next_field > fHeader->field_count) 1258 || (field->offset + field->name_length + field->data_size 1259 > fHeader->data_size)) { 1260 // the message is corrupt 1261 MakeEmpty(); 1262 return B_BAD_VALUE; 1263 } 1264 } 1265 1266 return B_OK; 1267 } 1268 1269 1270 status_t 1271 BMessage::Unflatten(const char* flatBuffer) 1272 { 1273 DEBUG_FUNCTION_ENTER; 1274 if (flatBuffer == NULL) 1275 return B_BAD_VALUE; 1276 1277 uint32 format = *(uint32*)flatBuffer; 1278 if (format != MESSAGE_FORMAT_HAIKU) 1279 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer); 1280 1281 // native message unflattening 1282 1283 _Clear(); 1284 1285 fHeader = (message_header*)malloc(sizeof(message_header)); 1286 if (fHeader == NULL) 1287 return B_NO_MEMORY; 1288 1289 memcpy(fHeader, flatBuffer, sizeof(message_header)); 1290 flatBuffer += sizeof(message_header); 1291 1292 if (fHeader->format != MESSAGE_FORMAT_HAIKU 1293 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1294 _InitHeader(); 1295 return B_BAD_VALUE; 1296 } 1297 1298 what = fHeader->what; 1299 1300 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0 1301 && fHeader->message_area >= 0) { 1302 status_t result = _Reference(); 1303 if (result != B_OK) { 1304 _InitHeader(); 1305 return result; 1306 } 1307 } else { 1308 fHeader->message_area = -1; 1309 1310 if (fHeader->field_count > 0) { 1311 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1312 fFields = (field_header*)malloc(fieldsSize); 1313 if (fFields == NULL) { 1314 _InitHeader(); 1315 return B_NO_MEMORY; 1316 } 1317 1318 memcpy(fFields, flatBuffer, fieldsSize); 1319 flatBuffer += fieldsSize; 1320 } 1321 1322 if (fHeader->data_size > 0) { 1323 fData = (uint8*)malloc(fHeader->data_size); 1324 if (fData == NULL) { 1325 free(fFields); 1326 fFields = NULL; 1327 _InitHeader(); 1328 return B_NO_MEMORY; 1329 } 1330 1331 memcpy(fData, flatBuffer, fHeader->data_size); 1332 } 1333 } 1334 1335 return _ValidateMessage(); 1336 } 1337 1338 1339 status_t 1340 BMessage::Unflatten(BDataIO* stream) 1341 { 1342 DEBUG_FUNCTION_ENTER; 1343 if (stream == NULL) 1344 return B_BAD_VALUE; 1345 1346 uint32 format = 0; 1347 stream->Read(&format, sizeof(uint32)); 1348 if (format != MESSAGE_FORMAT_HAIKU) 1349 return BPrivate::MessageAdapter::Unflatten(format, this, stream); 1350 1351 // native message unflattening 1352 1353 _Clear(); 1354 1355 fHeader = (message_header*)malloc(sizeof(message_header)); 1356 if (fHeader == NULL) 1357 return B_NO_MEMORY; 1358 1359 fHeader->format = format; 1360 uint8* header = (uint8*)fHeader; 1361 ssize_t result = stream->Read(header + sizeof(uint32), 1362 sizeof(message_header) - sizeof(uint32)); 1363 if (result != sizeof(message_header) - sizeof(uint32) 1364 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1365 _InitHeader(); 1366 return result < 0 ? result : B_BAD_VALUE; 1367 } 1368 1369 what = fHeader->what; 1370 1371 fHeader->message_area = -1; 1372 1373 if (fHeader->field_count > 0) { 1374 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1375 fFields = (field_header*)malloc(fieldsSize); 1376 if (fFields == NULL) { 1377 _InitHeader(); 1378 return B_NO_MEMORY; 1379 } 1380 1381 result = stream->Read(fFields, fieldsSize); 1382 if (result != fieldsSize) 1383 return result < 0 ? result : B_BAD_VALUE; 1384 } 1385 1386 if (fHeader->data_size > 0) { 1387 fData = (uint8*)malloc(fHeader->data_size); 1388 if (fData == NULL) { 1389 free(fFields); 1390 fFields = NULL; 1391 _InitHeader(); 1392 return B_NO_MEMORY; 1393 } 1394 1395 result = stream->Read(fData, fHeader->data_size); 1396 if (result != (ssize_t)fHeader->data_size) 1397 return result < 0 ? result : B_BAD_VALUE; 1398 } 1399 1400 return _ValidateMessage(); 1401 } 1402 1403 1404 status_t 1405 BMessage::AddSpecifier(const char* property) 1406 { 1407 DEBUG_FUNCTION_ENTER; 1408 BMessage message(B_DIRECT_SPECIFIER); 1409 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1410 if (result != B_OK) 1411 return result; 1412 1413 return AddSpecifier(&message); 1414 } 1415 1416 1417 status_t 1418 BMessage::AddSpecifier(const char* property, int32 index) 1419 { 1420 DEBUG_FUNCTION_ENTER; 1421 BMessage message(B_INDEX_SPECIFIER); 1422 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1423 if (result != B_OK) 1424 return result; 1425 1426 result = message.AddInt32("index", index); 1427 if (result != B_OK) 1428 return result; 1429 1430 return AddSpecifier(&message); 1431 } 1432 1433 1434 status_t 1435 BMessage::AddSpecifier(const char* property, int32 index, int32 range) 1436 { 1437 DEBUG_FUNCTION_ENTER; 1438 if (range < 0) 1439 return B_BAD_VALUE; 1440 1441 BMessage message(B_RANGE_SPECIFIER); 1442 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1443 if (result != B_OK) 1444 return result; 1445 1446 result = message.AddInt32("index", index); 1447 if (result != B_OK) 1448 return result; 1449 1450 result = message.AddInt32("range", range); 1451 if (result != B_OK) 1452 return result; 1453 1454 return AddSpecifier(&message); 1455 } 1456 1457 1458 status_t 1459 BMessage::AddSpecifier(const char* property, const char* name) 1460 { 1461 DEBUG_FUNCTION_ENTER; 1462 BMessage message(B_NAME_SPECIFIER); 1463 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1464 if (result != B_OK) 1465 return result; 1466 1467 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1468 if (result != B_OK) 1469 return result; 1470 1471 return AddSpecifier(&message); 1472 } 1473 1474 1475 status_t 1476 BMessage::AddSpecifier(const BMessage* specifier) 1477 { 1478 DEBUG_FUNCTION_ENTER; 1479 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1480 if (result != B_OK) 1481 return result; 1482 1483 fHeader->current_specifier++; 1484 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1485 return B_OK; 1486 } 1487 1488 1489 status_t 1490 BMessage::SetCurrentSpecifier(int32 index) 1491 { 1492 DEBUG_FUNCTION_ENTER; 1493 if (index < 0) 1494 return B_BAD_INDEX; 1495 1496 type_code type; 1497 int32 count; 1498 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1499 if (result != B_OK) 1500 return result; 1501 1502 if (index > count) 1503 return B_BAD_INDEX; 1504 1505 fHeader->current_specifier = index; 1506 return B_OK; 1507 } 1508 1509 1510 status_t 1511 BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what, 1512 const char** property) const 1513 { 1514 DEBUG_FUNCTION_ENTER; 1515 if (fHeader == NULL) 1516 return B_NO_INIT; 1517 1518 if (index != NULL) 1519 *index = fHeader->current_specifier; 1520 1521 if (fHeader->current_specifier < 0 1522 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1523 return B_BAD_SCRIPT_SYNTAX; 1524 1525 if (specifier) { 1526 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1527 specifier) != B_OK) 1528 return B_BAD_SCRIPT_SYNTAX; 1529 1530 if (_what != NULL) 1531 *_what = specifier->what; 1532 1533 if (property) { 1534 if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK) 1535 return B_BAD_SCRIPT_SYNTAX; 1536 } 1537 } 1538 1539 return B_OK; 1540 } 1541 1542 1543 bool 1544 BMessage::HasSpecifiers() const 1545 { 1546 DEBUG_FUNCTION_ENTER; 1547 return fHeader != NULL 1548 && (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0; 1549 } 1550 1551 1552 status_t 1553 BMessage::PopSpecifier() 1554 { 1555 DEBUG_FUNCTION_ENTER; 1556 if (fHeader == NULL) 1557 return B_NO_INIT; 1558 1559 if (fHeader->current_specifier < 0 || 1560 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1561 return B_BAD_VALUE; 1562 1563 if (fHeader->current_specifier >= 0) 1564 fHeader->current_specifier--; 1565 1566 return B_OK; 1567 } 1568 1569 1570 status_t 1571 BMessage::_ResizeData(uint32 offset, int32 change) 1572 { 1573 if (change == 0) 1574 return B_OK; 1575 1576 /* optimize for the most usual case: appending data */ 1577 if (offset < fHeader->data_size) { 1578 field_header* field = fFields; 1579 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 1580 if (field->offset >= offset) 1581 field->offset += change; 1582 } 1583 } 1584 1585 if (change > 0) { 1586 if (fDataAvailable >= (uint32)change) { 1587 if (offset < fHeader->data_size) { 1588 memmove(fData + offset + change, fData + offset, 1589 fHeader->data_size - offset); 1590 } 1591 1592 fDataAvailable -= change; 1593 fHeader->data_size += change; 1594 return B_OK; 1595 } 1596 1597 size_t size = fHeader->data_size * 2; 1598 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1599 size = max_c(size, fHeader->data_size + change); 1600 1601 uint8* newData = (uint8*)realloc(fData, size); 1602 if (size > 0 && newData == NULL) 1603 return B_NO_MEMORY; 1604 1605 fData = newData; 1606 if (offset < fHeader->data_size) { 1607 memmove(fData + offset + change, fData + offset, 1608 fHeader->data_size - offset); 1609 } 1610 1611 fHeader->data_size += change; 1612 fDataAvailable = size - fHeader->data_size; 1613 } else { 1614 ssize_t length = fHeader->data_size - offset + change; 1615 if (length > 0) 1616 memmove(fData + offset, fData + offset - change, length); 1617 1618 // change is negative 1619 fHeader->data_size += change; 1620 fDataAvailable -= change; 1621 1622 if (fDataAvailable > MAX_DATA_PREALLOCATION) { 1623 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1624 ssize_t size = fHeader->data_size + available; 1625 uint8* newData = (uint8*)realloc(fData, size); 1626 if (size > 0 && newData == NULL) { 1627 // this is strange, but not really fatal 1628 return B_OK; 1629 } 1630 1631 fData = newData; 1632 fDataAvailable = available; 1633 } 1634 } 1635 1636 return B_OK; 1637 } 1638 1639 1640 uint32 1641 BMessage::_HashName(const char* name) const 1642 { 1643 char ch; 1644 uint32 result = 0; 1645 1646 while ((ch = *name++) != 0) { 1647 result = (result << 7) ^ (result >> 24); 1648 result ^= ch; 1649 } 1650 1651 result ^= result << 12; 1652 return result; 1653 } 1654 1655 1656 status_t 1657 BMessage::_FindField(const char* name, type_code type, field_header** result) 1658 const 1659 { 1660 if (name == NULL) 1661 return B_BAD_VALUE; 1662 1663 if (fHeader == NULL) 1664 return B_NO_INIT; 1665 1666 if (fHeader->field_count == 0 || fFields == NULL || fData == NULL) 1667 return B_NAME_NOT_FOUND; 1668 1669 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1670 int32 nextField = fHeader->hash_table[hash]; 1671 1672 while (nextField >= 0) { 1673 field_header* field = &fFields[nextField]; 1674 if ((field->flags & FIELD_FLAG_VALID) == 0) 1675 break; 1676 1677 if (strncmp((const char*)(fData + field->offset), name, 1678 field->name_length) == 0) { 1679 if (type != B_ANY_TYPE && field->type != type) 1680 return B_BAD_TYPE; 1681 1682 *result = field; 1683 return B_OK; 1684 } 1685 1686 nextField = field->next_field; 1687 } 1688 1689 return B_NAME_NOT_FOUND; 1690 } 1691 1692 1693 status_t 1694 BMessage::_AddField(const char* name, type_code type, bool isFixedSize, 1695 field_header** result) 1696 { 1697 if (fHeader == NULL) 1698 return B_NO_INIT; 1699 1700 if (fFieldsAvailable <= 0) { 1701 uint32 count = fHeader->field_count * 2 + 1; 1702 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1703 1704 field_header* newFields = (field_header*)realloc(fFields, 1705 count * sizeof(field_header)); 1706 if (count > 0 && newFields == NULL) 1707 return B_NO_MEMORY; 1708 1709 fFields = newFields; 1710 fFieldsAvailable = count - fHeader->field_count; 1711 } 1712 1713 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1714 int32* nextField = &fHeader->hash_table[hash]; 1715 while (*nextField >= 0) 1716 nextField = &fFields[*nextField].next_field; 1717 *nextField = fHeader->field_count; 1718 1719 field_header* field = &fFields[fHeader->field_count]; 1720 field->type = type; 1721 field->count = 0; 1722 field->data_size = 0; 1723 field->next_field = -1; 1724 field->offset = fHeader->data_size; 1725 field->name_length = strlen(name) + 1; 1726 status_t status = _ResizeData(field->offset, field->name_length); 1727 if (status != B_OK) 1728 return status; 1729 1730 memcpy(fData + field->offset, name, field->name_length); 1731 field->flags = FIELD_FLAG_VALID; 1732 if (isFixedSize) 1733 field->flags |= FIELD_FLAG_FIXED_SIZE; 1734 1735 fFieldsAvailable--; 1736 fHeader->field_count++; 1737 *result = field; 1738 return B_OK; 1739 } 1740 1741 1742 status_t 1743 BMessage::_RemoveField(field_header* field) 1744 { 1745 status_t result = _ResizeData(field->offset, -(field->data_size 1746 + field->name_length)); 1747 if (result != B_OK) 1748 return result; 1749 1750 int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header); 1751 int32 nextField = field->next_field; 1752 if (nextField > index) 1753 nextField--; 1754 1755 int32* value = fHeader->hash_table; 1756 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1757 if (*value > index) 1758 *value -= 1; 1759 else if (*value == index) 1760 *value = nextField; 1761 } 1762 1763 field_header* other = fFields; 1764 for (uint32 i = 0; i < fHeader->field_count; i++, other++) { 1765 if (other->next_field > index) 1766 other->next_field--; 1767 else if (other->next_field == index) 1768 other->next_field = nextField; 1769 } 1770 1771 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header); 1772 memmove(fFields + index, fFields + index + 1, size); 1773 fHeader->field_count--; 1774 fFieldsAvailable++; 1775 1776 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) { 1777 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1778 size = (fHeader->field_count + available) * sizeof(field_header); 1779 field_header* newFields = (field_header*)realloc(fFields, size); 1780 if (size > 0 && newFields == NULL) { 1781 // this is strange, but not really fatal 1782 return B_OK; 1783 } 1784 1785 fFields = newFields; 1786 fFieldsAvailable = available; 1787 } 1788 1789 return B_OK; 1790 } 1791 1792 1793 status_t 1794 BMessage::AddData(const char* name, type_code type, const void* data, 1795 ssize_t numBytes, bool isFixedSize, int32 count) 1796 { 1797 // Note that the "count" argument is only a hint at how many items 1798 // the caller expects to add to this field. Since we do no item pre- 1799 // allocation, we ignore this argument. 1800 DEBUG_FUNCTION_ENTER; 1801 if (numBytes <= 0 || data == NULL) 1802 return B_BAD_VALUE; 1803 1804 if (fHeader == NULL) 1805 return B_NO_INIT; 1806 1807 status_t result; 1808 if (fHeader->message_area >= 0) { 1809 result = _CopyForWrite(); 1810 if (result != B_OK) 1811 return result; 1812 } 1813 1814 field_header* field = NULL; 1815 result = _FindField(name, type, &field); 1816 if (result == B_NAME_NOT_FOUND) 1817 result = _AddField(name, type, isFixedSize, &field); 1818 1819 if (result != B_OK) 1820 return result; 1821 1822 if (field == NULL) 1823 return B_ERROR; 1824 1825 uint32 offset = field->offset + field->name_length + field->data_size; 1826 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1827 if (field->count) { 1828 ssize_t size = field->data_size / field->count; 1829 if (size != numBytes) 1830 return B_BAD_VALUE; 1831 } 1832 1833 result = _ResizeData(offset, numBytes); 1834 if (result != B_OK) { 1835 if (field->count == 0) 1836 _RemoveField(field); 1837 return result; 1838 } 1839 1840 memcpy(fData + offset, data, numBytes); 1841 field->data_size += numBytes; 1842 } else { 1843 int32 change = numBytes + sizeof(uint32); 1844 result = _ResizeData(offset, change); 1845 if (result != B_OK) { 1846 if (field->count == 0) 1847 _RemoveField(field); 1848 return result; 1849 } 1850 1851 uint32 size = (uint32)numBytes; 1852 memcpy(fData + offset, &size, sizeof(uint32)); 1853 memcpy(fData + offset + sizeof(uint32), data, size); 1854 field->data_size += change; 1855 } 1856 1857 field->count++; 1858 return B_OK; 1859 } 1860 1861 1862 status_t 1863 BMessage::RemoveData(const char* name, int32 index) 1864 { 1865 DEBUG_FUNCTION_ENTER; 1866 if (index < 0) 1867 return B_BAD_INDEX; 1868 1869 if (fHeader == NULL) 1870 return B_NO_INIT; 1871 1872 status_t result; 1873 if (fHeader->message_area >= 0) { 1874 result = _CopyForWrite(); 1875 if (result != B_OK) 1876 return result; 1877 } 1878 1879 field_header* field = NULL; 1880 result = _FindField(name, B_ANY_TYPE, &field); 1881 if (result != B_OK) 1882 return result; 1883 1884 if ((uint32)index >= field->count) 1885 return B_BAD_INDEX; 1886 1887 if (field->count == 1) 1888 return _RemoveField(field); 1889 1890 uint32 offset = field->offset + field->name_length; 1891 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1892 ssize_t size = field->data_size / field->count; 1893 result = _ResizeData(offset + index * size, -size); 1894 if (result != B_OK) 1895 return result; 1896 1897 field->data_size -= size; 1898 } else { 1899 uint8* pointer = fData + offset; 1900 for (int32 i = 0; i < index; i++) { 1901 offset += *(uint32*)pointer + sizeof(uint32); 1902 pointer = fData + offset; 1903 } 1904 1905 size_t currentSize = *(uint32*)pointer + sizeof(uint32); 1906 result = _ResizeData(offset, -currentSize); 1907 if (result != B_OK) 1908 return result; 1909 1910 field->data_size -= currentSize; 1911 } 1912 1913 field->count--; 1914 return B_OK; 1915 } 1916 1917 1918 status_t 1919 BMessage::RemoveName(const char* name) 1920 { 1921 DEBUG_FUNCTION_ENTER; 1922 if (fHeader == NULL) 1923 return B_NO_INIT; 1924 1925 status_t result; 1926 if (fHeader->message_area >= 0) { 1927 result = _CopyForWrite(); 1928 if (result != B_OK) 1929 return result; 1930 } 1931 1932 field_header* field = NULL; 1933 result = _FindField(name, B_ANY_TYPE, &field); 1934 if (result != B_OK) 1935 return result; 1936 1937 return _RemoveField(field); 1938 } 1939 1940 1941 status_t 1942 BMessage::MakeEmpty() 1943 { 1944 DEBUG_FUNCTION_ENTER; 1945 _Clear(); 1946 return _InitHeader(); 1947 } 1948 1949 1950 status_t 1951 BMessage::FindData(const char* name, type_code type, int32 index, 1952 const void** data, ssize_t* numBytes) const 1953 { 1954 DEBUG_FUNCTION_ENTER; 1955 if (data == NULL) 1956 return B_BAD_VALUE; 1957 1958 *data = NULL; 1959 field_header* field = NULL; 1960 status_t result = _FindField(name, type, &field); 1961 if (result != B_OK) 1962 return result; 1963 1964 if (index < 0 || (uint32)index >= field->count) 1965 return B_BAD_INDEX; 1966 1967 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1968 size_t bytes = field->data_size / field->count; 1969 *data = fData + field->offset + field->name_length + index * bytes; 1970 if (numBytes != NULL) 1971 *numBytes = bytes; 1972 } else { 1973 uint8* pointer = fData + field->offset + field->name_length; 1974 for (int32 i = 0; i < index; i++) 1975 pointer += *(uint32*)pointer + sizeof(uint32); 1976 1977 *data = pointer + sizeof(uint32); 1978 if (numBytes != NULL) 1979 *numBytes = *(uint32*)pointer; 1980 } 1981 1982 return B_OK; 1983 } 1984 1985 1986 status_t 1987 BMessage::ReplaceData(const char* name, type_code type, int32 index, 1988 const void* data, ssize_t numBytes) 1989 { 1990 DEBUG_FUNCTION_ENTER; 1991 if (numBytes <= 0 || data == NULL) 1992 return B_BAD_VALUE; 1993 1994 field_header* field = NULL; 1995 status_t result = _FindField(name, type, &field); 1996 if (result != B_OK) 1997 return result; 1998 1999 if (index < 0 || (uint32)index >= field->count) 2000 return B_BAD_INDEX; 2001 2002 if (fHeader->message_area >= 0) { 2003 result = _CopyForWrite(); 2004 if (result != B_OK) 2005 return result; 2006 } 2007 2008 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 2009 ssize_t size = field->data_size / field->count; 2010 if (size != numBytes) 2011 return B_BAD_VALUE; 2012 2013 memcpy(fData + field->offset + field->name_length + index * size, data, 2014 size); 2015 } else { 2016 uint32 offset = field->offset + field->name_length; 2017 uint8* pointer = fData + offset; 2018 2019 for (int32 i = 0; i < index; i++) { 2020 offset += *(uint32*)pointer + sizeof(uint32); 2021 pointer = fData + offset; 2022 } 2023 2024 size_t currentSize = *(uint32*)pointer; 2025 int32 change = numBytes - currentSize; 2026 result = _ResizeData(offset, change); 2027 if (result != B_OK) 2028 return result; 2029 2030 uint32 newSize = (uint32)numBytes; 2031 memcpy(fData + offset, &newSize, sizeof(uint32)); 2032 memcpy(fData + offset + sizeof(uint32), data, newSize); 2033 field->data_size += change; 2034 } 2035 2036 return B_OK; 2037 } 2038 2039 2040 bool 2041 BMessage::HasData(const char* name, type_code type, int32 index) const 2042 { 2043 DEBUG_FUNCTION_ENTER; 2044 field_header* field = NULL; 2045 status_t result = _FindField(name, type, &field); 2046 if (result != B_OK) 2047 return false; 2048 2049 if (index < 0 || (uint32)index >= field->count) 2050 return false; 2051 2052 return true; 2053 } 2054 2055 2056 /* Static functions for cache initialization and cleanup */ 2057 void 2058 BMessage::_StaticInit() 2059 { 2060 DEBUG_FUNCTION_ENTER2; 2061 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2062 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2063 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2064 2065 sReplyPortInUse[0] = 0; 2066 sReplyPortInUse[1] = 0; 2067 sReplyPortInUse[2] = 0; 2068 2069 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 2070 } 2071 2072 2073 void 2074 BMessage::_StaticReInitForkedChild() 2075 { 2076 DEBUG_FUNCTION_ENTER2; 2077 2078 // overwrite the inherited ports with a set of our own 2079 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2080 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2081 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2082 2083 sReplyPortInUse[0] = 0; 2084 sReplyPortInUse[1] = 0; 2085 sReplyPortInUse[2] = 0; 2086 } 2087 2088 2089 void 2090 BMessage::_StaticCleanup() 2091 { 2092 DEBUG_FUNCTION_ENTER2; 2093 delete_port(sReplyPorts[0]); 2094 sReplyPorts[0] = -1; 2095 delete_port(sReplyPorts[1]); 2096 sReplyPorts[1] = -1; 2097 delete_port(sReplyPorts[2]); 2098 sReplyPorts[2] = -1; 2099 } 2100 2101 2102 void 2103 BMessage::_StaticCacheCleanup() 2104 { 2105 DEBUG_FUNCTION_ENTER2; 2106 delete sMsgCache; 2107 sMsgCache = NULL; 2108 } 2109 2110 2111 int32 2112 BMessage::_StaticGetCachedReplyPort() 2113 { 2114 DEBUG_FUNCTION_ENTER2; 2115 int index = -1; 2116 for (int32 i = 0; i < sNumReplyPorts; i++) { 2117 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 2118 if (old == 0) { 2119 // This entry is free 2120 index = i; 2121 break; 2122 } else { 2123 // This entry is being used. 2124 atomic_add(&(sReplyPortInUse[i]), -1); 2125 } 2126 } 2127 2128 return index; 2129 } 2130 2131 2132 status_t 2133 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2134 bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const 2135 { 2136 DEBUG_FUNCTION_ENTER; 2137 ssize_t size = 0; 2138 char* buffer = NULL; 2139 message_header* header = NULL; 2140 status_t result = B_OK; 2141 2142 BPrivate::BDirectMessageTarget* direct = NULL; 2143 BMessage* copy = NULL; 2144 if (portOwner == BPrivate::current_team()) 2145 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct); 2146 2147 if (direct != NULL) { 2148 // We have a direct local message target - we can just enqueue the 2149 // message in its message queue. This will also prevent possible 2150 // deadlocks when the queue is full. 2151 copy = new BMessage(*this); 2152 if (copy != NULL) { 2153 header = copy->fHeader; 2154 header->flags = fHeader->flags; 2155 } else { 2156 direct->Release(); 2157 return B_NO_MEMORY; 2158 } 2159 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2160 } else if (fHeader->data_size > B_PAGE_SIZE * 10) { 2161 // ToDo: bind the above size to the max port message size 2162 // use message passing by area for such a large message 2163 result = _FlattenToArea(&header); 2164 if (result != B_OK) 2165 return result; 2166 2167 buffer = (char*)header; 2168 size = sizeof(message_header); 2169 2170 if (header->message_area >= 0) { 2171 team_id target = portOwner; 2172 if (target < 0) { 2173 port_info info; 2174 result = get_port_info(port, &info); 2175 if (result != B_OK) { 2176 free(header); 2177 return result; 2178 } 2179 target = info.team; 2180 } 2181 2182 void* address = NULL; 2183 area_id transfered = _kern_transfer_area(header->message_area, 2184 &address, B_ANY_ADDRESS, target); 2185 if (transfered < 0) { 2186 delete_area(header->message_area); 2187 free(header); 2188 return transfered; 2189 } 2190 2191 header->message_area = transfered; 2192 } 2193 #endif 2194 } else { 2195 size = FlattenedSize(); 2196 buffer = (char*)malloc(size); 2197 if (buffer == NULL) 2198 return B_NO_MEMORY; 2199 2200 result = Flatten(buffer, size); 2201 if (result != B_OK) { 2202 free(buffer); 2203 return result; 2204 } 2205 2206 header = (message_header*)buffer; 2207 } 2208 2209 if (!replyTo.IsValid()) { 2210 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 2211 fHeader->reply_port, fHeader->reply_target); 2212 2213 if (!replyTo.IsValid()) 2214 replyTo = be_app_messenger; 2215 } 2216 2217 BMessenger::Private replyToPrivate(replyTo); 2218 2219 if (replyRequired) { 2220 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 2221 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 2222 } 2223 2224 header->target = token; 2225 header->reply_team = replyToPrivate.Team(); 2226 header->reply_port = replyToPrivate.Port(); 2227 header->reply_target = replyToPrivate.Token(); 2228 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2229 2230 if (direct == NULL) { 2231 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2232 "message: '%c%c%c%c'", portOwner, port, token, 2233 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2234 2235 do { 2236 result = write_port_etc(port, kPortMessageCode, (void*)buffer, 2237 size, B_RELATIVE_TIMEOUT, timeout); 2238 } while (result == B_INTERRUPTED); 2239 } 2240 2241 if (result == B_OK && IsSourceWaiting()) { 2242 // the forwarded message will handle the reply - we must not do 2243 // this anymore 2244 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2245 } 2246 2247 // we need to do this last because it is possible our 2248 // message might be destroyed after it's enqueued in the 2249 // target looper. Thus we don't want to do any ops that depend on 2250 // members of this after the enqueue. 2251 if (direct != NULL) { 2252 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2253 "message: '%c%c%c%c'", port, token, 2254 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2255 2256 // this is a local message transmission 2257 direct->AddMessage(copy); 2258 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2259 // there is currently no message waiting, and we need to wakeup the 2260 // looper 2261 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2262 } 2263 direct->Release(); 2264 } 2265 2266 free(buffer); 2267 return result; 2268 } 2269 2270 2271 // Sends a message and waits synchronously for a reply. 2272 status_t 2273 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2274 BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2275 { 2276 if (IsSourceWaiting()) { 2277 // we can't forward this message synchronously when it's already 2278 // waiting for a reply 2279 return B_ERROR; 2280 } 2281 2282 DEBUG_FUNCTION_ENTER; 2283 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2284 port_id replyPort = B_BAD_PORT_ID; 2285 status_t result = B_OK; 2286 2287 if (cachedReplyPort < 0) { 2288 // All the cached reply ports are in use; create a new one 2289 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2290 if (replyPort < 0) 2291 return replyPort; 2292 } else { 2293 assert(cachedReplyPort < sNumReplyPorts); 2294 replyPort = sReplyPorts[cachedReplyPort]; 2295 } 2296 2297 team_id team = B_BAD_TEAM_ID; 2298 if (be_app != NULL) 2299 team = be_app->Team(); 2300 else { 2301 port_info portInfo; 2302 result = get_port_info(replyPort, &portInfo); 2303 if (result != B_OK) 2304 goto error; 2305 2306 team = portInfo.team; 2307 } 2308 2309 result = set_port_owner(replyPort, portOwner); 2310 if (result != B_OK) 2311 goto error; 2312 2313 // tests if the queue of the reply port is really empty 2314 #if 0 2315 port_info portInfo; 2316 if (get_port_info(replyPort, &portInfo) == B_OK 2317 && portInfo.queue_count > 0) { 2318 debugger("reply port not empty!"); 2319 printf(" reply port not empty! %ld message(s) in queue\n", 2320 portInfo.queue_count); 2321 2322 // fetch and print the messages 2323 for (int32 i = 0; i < portInfo.queue_count; i++) { 2324 char buffer[1024]; 2325 int32 code; 2326 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2327 if (size < 0) { 2328 printf("failed to read message from reply port\n"); 2329 continue; 2330 } 2331 if (size >= (ssize_t)sizeof(buffer)) { 2332 printf("message from reply port too big\n"); 2333 continue; 2334 } 2335 2336 BMemoryIO stream(buffer, size); 2337 BMessage reply; 2338 if (reply.Unflatten(&stream) != B_OK) { 2339 printf("failed to unflatten message from reply port\n"); 2340 continue; 2341 } 2342 2343 printf("message %ld from reply port:\n", i); 2344 reply.PrintToStream(); 2345 } 2346 } 2347 #endif 2348 2349 { 2350 BMessenger replyTarget; 2351 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2352 B_PREFERRED_TOKEN); 2353 // TODO: replying could also use a BDirectMessageTarget like mechanism 2354 // for local targets 2355 result = _SendMessage(port, -1, token, sendTimeout, true, 2356 replyTarget); 2357 } 2358 2359 if (result != B_OK) 2360 goto error; 2361 2362 int32 code; 2363 result = handle_reply(replyPort, &code, replyTimeout, reply); 2364 if (result != B_OK && cachedReplyPort >= 0) { 2365 delete_port(replyPort); 2366 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2367 } 2368 2369 error: 2370 if (cachedReplyPort >= 0) { 2371 // Reclaim ownership of cached port 2372 set_port_owner(replyPort, team); 2373 // Flag as available 2374 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2375 return result; 2376 } 2377 2378 delete_port(replyPort); 2379 return result; 2380 } 2381 2382 2383 status_t 2384 BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port, 2385 int32 token, bigtime_t timeout) 2386 { 2387 DEBUG_FUNCTION_ENTER2; 2388 if (data == NULL) 2389 return B_BAD_VALUE; 2390 2391 uint32 magic = *(uint32*)data; 2392 2393 if (magic == MESSAGE_FORMAT_HAIKU 2394 || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2395 message_header* header = (message_header*)data; 2396 header->target = token; 2397 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2398 } else if (magic == MESSAGE_FORMAT_R5) { 2399 uint8* header = (uint8*)data; 2400 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2401 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2402 + sizeof(uint8) /* flags */; 2403 *(int32*)header = token; 2404 } else if (((KMessage::Header*)data)->magic 2405 == KMessage::kMessageHeaderMagic) { 2406 KMessage::Header* header = (KMessage::Header*)data; 2407 header->targetToken = token; 2408 } else { 2409 return B_NOT_A_MESSAGE; 2410 } 2411 2412 // send the message 2413 status_t result; 2414 2415 do { 2416 result = write_port_etc(port, kPortMessageCode, data, size, 2417 B_RELATIVE_TIMEOUT, timeout); 2418 } while (result == B_INTERRUPTED); 2419 2420 return result; 2421 } 2422 2423 2424 void BMessage::_ReservedMessage1() {} 2425 void BMessage::_ReservedMessage2() {} 2426 void BMessage::_ReservedMessage3() {} 2427 2428 2429 // #pragma mark - Macro definitions for data access methods 2430 2431 2432 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2433 2434 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2435 status_t \ 2436 BMessage::Add##typeName(const char* name, type val) \ 2437 { \ 2438 return AddData(name, typeCode, &val, sizeof(type), true); \ 2439 } \ 2440 \ 2441 \ 2442 status_t \ 2443 BMessage::Find##typeName(const char* name, type* p) const \ 2444 { \ 2445 void* ptr = NULL; \ 2446 ssize_t bytes = 0; \ 2447 status_t error = B_OK; \ 2448 \ 2449 *p = type(); \ 2450 error = FindData(name, typeCode, 0, (const void**)&ptr, &bytes); \ 2451 \ 2452 if (error == B_OK) \ 2453 memcpy(p, ptr, sizeof(type)); \ 2454 \ 2455 return error; \ 2456 } \ 2457 \ 2458 \ 2459 status_t \ 2460 BMessage::Find##typeName(const char* name, int32 index, type* p) const \ 2461 { \ 2462 void* ptr = NULL; \ 2463 ssize_t bytes = 0; \ 2464 status_t error = B_OK; \ 2465 \ 2466 *p = type(); \ 2467 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \ 2468 \ 2469 if (error == B_OK) \ 2470 memcpy(p, ptr, sizeof(type)); \ 2471 \ 2472 return error; \ 2473 } \ 2474 \ 2475 \ 2476 status_t \ 2477 BMessage::Replace##typeName(const char* name, type value) \ 2478 { \ 2479 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \ 2480 } \ 2481 \ 2482 \ 2483 status_t \ 2484 BMessage::Replace##typeName(const char* name, int32 index, type value) \ 2485 { \ 2486 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \ 2487 } \ 2488 \ 2489 \ 2490 bool \ 2491 BMessage::Has##typeName(const char* name, int32 index) const \ 2492 { \ 2493 return HasData(name, typeCode, index); \ 2494 } 2495 2496 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2497 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2498 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2499 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2500 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2501 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2502 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2503 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2504 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2505 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2506 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2507 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2508 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2509 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2510 2511 #undef DEFINE_FUNCTIONS 2512 2513 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2514 bool \ 2515 BMessage::Has##typeName(const char* name, int32 index) const \ 2516 { \ 2517 return HasData(name, typeCode, index); \ 2518 } 2519 2520 2521 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE); 2522 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2523 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2524 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2525 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2526 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2527 2528 #undef DEFINE_HAS_FUNCTION 2529 2530 2531 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2532 type \ 2533 BMessage::Find##typeName(const char* name, int32 index) const \ 2534 { \ 2535 type val = initialize; \ 2536 Find##typeName(name, index, &val); \ 2537 return val; \ 2538 } 2539 2540 2541 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2542 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2543 DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL); 2544 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2545 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2546 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2547 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2548 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2549 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2550 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2551 2552 #undef DEFINE_LAZY_FIND_FUNCTION 2553 2554 2555 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \ 2556 type \ 2557 BMessage::Get##typeName(const char* name, type defaultValue) const \ 2558 { \ 2559 return Get##typeName(name, 0, defaultValue); \ 2560 } \ 2561 \ 2562 \ 2563 type \ 2564 BMessage::Get##typeName(const char* name, int32 index, \ 2565 type defaultValue) const \ 2566 { \ 2567 type value; \ 2568 if (Find##typeName(name, index, &value) == B_OK) \ 2569 return value; \ 2570 \ 2571 return defaultValue; \ 2572 } \ 2573 \ 2574 \ 2575 status_t \ 2576 BMessage::Set##typeName(const char* name, type value) \ 2577 { \ 2578 return SetData(name, typeCode, &value, sizeof(type)); \ 2579 } \ 2580 2581 2582 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2583 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2584 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2585 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2586 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2587 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2588 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2589 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2590 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2591 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2592 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2593 2594 #undef DEFINE_SET_GET_FUNCTION 2595 2596 2597 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \ 2598 type \ 2599 BMessage::Get##typeName(const char* name, const type& defaultValue) const \ 2600 { \ 2601 return Get##typeName(name, 0, defaultValue); \ 2602 } \ 2603 \ 2604 \ 2605 type \ 2606 BMessage::Get##typeName(const char* name, int32 index, \ 2607 const type& defaultValue) const \ 2608 { \ 2609 type value; \ 2610 if (Find##typeName(name, index, &value) == B_OK) \ 2611 return value; \ 2612 \ 2613 return defaultValue; \ 2614 } \ 2615 \ 2616 \ 2617 status_t \ 2618 BMessage::Set##typeName(const char* name, const type& value) \ 2619 { \ 2620 return SetData(name, typeCode, &value, sizeof(type)); \ 2621 } \ 2622 2623 2624 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2625 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2626 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2627 2628 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS 2629 2630 2631 status_t 2632 BMessage::AddAlignment(const char* name, const BAlignment& alignment) 2633 { 2634 int32 data[2] = { alignment.horizontal, alignment.vertical }; 2635 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data)); 2636 } 2637 2638 2639 status_t 2640 BMessage::AddString(const char* name, const char* string) 2641 { 2642 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, 2643 false); 2644 } 2645 2646 2647 status_t 2648 BMessage::AddString(const char* name, const BString& string) 2649 { 2650 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, 2651 false); 2652 } 2653 2654 2655 status_t 2656 BMessage::AddStrings(const char* name, const BStringList& list) 2657 { 2658 int32 count = list.CountStrings(); 2659 for (int32 i = 0; i < count; i++) { 2660 status_t error = AddString(name, list.StringAt(i)); 2661 if (error != B_OK) 2662 return error; 2663 } 2664 2665 return B_OK; 2666 } 2667 2668 2669 status_t 2670 BMessage::AddPointer(const char* name, const void* pointer) 2671 { 2672 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2673 } 2674 2675 2676 status_t 2677 BMessage::AddMessenger(const char* name, BMessenger messenger) 2678 { 2679 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2680 } 2681 2682 2683 status_t 2684 BMessage::AddRef(const char* name, const entry_ref* ref) 2685 { 2686 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2687 char buffer[size]; 2688 2689 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2690 2691 if (error >= B_OK) 2692 error = AddData(name, B_REF_TYPE, buffer, size, false); 2693 2694 return error; 2695 } 2696 2697 2698 status_t 2699 BMessage::AddMessage(const char* name, const BMessage* message) 2700 { 2701 if (message == NULL) 2702 return B_BAD_VALUE; 2703 2704 // TODO: This and the following functions waste time by allocating and 2705 // copying an extra buffer. Functions can be added that return a direct 2706 // pointer into the message. 2707 2708 char stackBuffer[16384]; 2709 ssize_t size = message->FlattenedSize(); 2710 2711 char* buffer; 2712 if (size > (ssize_t)sizeof(stackBuffer)) { 2713 buffer = (char*)malloc(size); 2714 if (buffer == NULL) 2715 return B_NO_MEMORY; 2716 } else 2717 buffer = stackBuffer; 2718 2719 status_t error = message->Flatten(buffer, size); 2720 2721 if (error >= B_OK) 2722 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2723 2724 if (buffer != stackBuffer) 2725 free(buffer); 2726 2727 return error; 2728 } 2729 2730 2731 status_t 2732 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count) 2733 { 2734 return AddFlat(name, (const BFlattenable*)object, count); 2735 } 2736 2737 2738 status_t 2739 BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count) 2740 { 2741 if (object == NULL) 2742 return B_BAD_VALUE; 2743 2744 char stackBuffer[16384]; 2745 ssize_t size = object->FlattenedSize(); 2746 2747 char* buffer; 2748 if (size > (ssize_t)sizeof(stackBuffer)) { 2749 buffer = (char*)malloc(size); 2750 if (buffer == NULL) 2751 return B_NO_MEMORY; 2752 } else 2753 buffer = stackBuffer; 2754 2755 status_t error = object->Flatten(buffer, size); 2756 2757 if (error >= B_OK) 2758 error = AddData(name, object->TypeCode(), buffer, size, false); 2759 2760 if (buffer != stackBuffer) 2761 free(buffer); 2762 2763 return error; 2764 } 2765 2766 2767 status_t 2768 BMessage::Append(const BMessage& other) 2769 { 2770 field_header* field = other.fFields; 2771 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) { 2772 const char* name = (const char*)(other.fData + field->offset); 2773 const void* data = (const void*)(other.fData + field->offset 2774 + field->name_length); 2775 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 2776 size_t size = field->data_size / field->count; 2777 2778 for (uint32 j = 0; j < field->count; j++) { 2779 if (!isFixed) { 2780 size = *(uint32*)data; 2781 data = (const void*)((const char*)data + sizeof(uint32)); 2782 } 2783 2784 status_t status = AddData(name, field->type, data, size, 2785 isFixed, 1); 2786 if (status != B_OK) 2787 return status; 2788 2789 data = (const void*)((const char*)data + size); 2790 } 2791 } 2792 return B_OK; 2793 } 2794 2795 2796 status_t 2797 BMessage::FindAlignment(const char* name, BAlignment* alignment) const 2798 { 2799 return FindAlignment(name, 0, alignment); 2800 } 2801 2802 2803 status_t 2804 BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment) 2805 const 2806 { 2807 if (!alignment) 2808 return B_BAD_VALUE; 2809 2810 int32* data; 2811 ssize_t bytes; 2812 2813 status_t err = FindData(name, B_ALIGNMENT_TYPE, index, 2814 (const void**)&data, &bytes); 2815 2816 if (err == B_OK) { 2817 if (bytes != sizeof(int32[2])) 2818 return B_ERROR; 2819 2820 alignment->horizontal = (enum alignment)(*data); 2821 alignment->vertical = (vertical_alignment)*(data + 1); 2822 } 2823 2824 return err; 2825 } 2826 2827 2828 status_t 2829 BMessage::FindString(const char* name, const char** string) const 2830 { 2831 return FindString(name, 0, string); 2832 } 2833 2834 2835 status_t 2836 BMessage::FindString(const char* name, int32 index, const char** string) const 2837 { 2838 ssize_t bytes; 2839 return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes); 2840 } 2841 2842 2843 status_t 2844 BMessage::FindString(const char* name, BString* string) const 2845 { 2846 return FindString(name, 0, string); 2847 } 2848 2849 2850 status_t 2851 BMessage::FindString(const char* name, int32 index, BString* string) const 2852 { 2853 if (string == NULL) 2854 return B_BAD_VALUE; 2855 2856 const char* value; 2857 status_t error = FindString(name, index, &value); 2858 2859 // Find*() clobbers the object even on failure 2860 string->SetTo(value); 2861 return error; 2862 } 2863 2864 2865 status_t 2866 BMessage::FindStrings(const char* name, BStringList* list) const 2867 { 2868 if (list == NULL) 2869 return B_BAD_VALUE; 2870 2871 list->MakeEmpty(); 2872 2873 // get the number of items 2874 type_code type; 2875 int32 count; 2876 if (GetInfo(name, &type, &count) != B_OK) 2877 return B_NAME_NOT_FOUND; 2878 2879 if (type != B_STRING_TYPE) 2880 return B_BAD_DATA; 2881 2882 for (int32 i = 0; i < count; i++) { 2883 BString string; 2884 status_t error = FindString(name, i, &string); 2885 if (error != B_OK) 2886 return error; 2887 if (!list->Add(string)) 2888 return B_NO_MEMORY; 2889 } 2890 2891 return B_OK; 2892 } 2893 2894 2895 status_t 2896 BMessage::FindPointer(const char* name, void** pointer) const 2897 { 2898 return FindPointer(name, 0, pointer); 2899 } 2900 2901 2902 status_t 2903 BMessage::FindPointer(const char* name, int32 index, void** pointer) const 2904 { 2905 if (pointer == NULL) 2906 return B_BAD_VALUE; 2907 2908 void** data = NULL; 2909 ssize_t size = 0; 2910 status_t error = FindData(name, B_POINTER_TYPE, index, 2911 (const void**)&data, &size); 2912 2913 if (error == B_OK) 2914 *pointer = *data; 2915 else 2916 *pointer = NULL; 2917 2918 return error; 2919 } 2920 2921 2922 status_t 2923 BMessage::FindMessenger(const char* name, BMessenger* messenger) const 2924 { 2925 return FindMessenger(name, 0, messenger); 2926 } 2927 2928 2929 status_t 2930 BMessage::FindMessenger(const char* name, int32 index, 2931 BMessenger* messenger) const 2932 { 2933 if (messenger == NULL) 2934 return B_BAD_VALUE; 2935 2936 void* data = NULL; 2937 ssize_t size = 0; 2938 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2939 (const void**)&data, &size); 2940 2941 if (error == B_OK) 2942 memcpy(messenger, data, sizeof(BMessenger)); 2943 else 2944 *messenger = BMessenger(); 2945 2946 return error; 2947 } 2948 2949 2950 status_t 2951 BMessage::FindRef(const char* name, entry_ref* ref) const 2952 { 2953 return FindRef(name, 0, ref); 2954 } 2955 2956 2957 status_t 2958 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const 2959 { 2960 if (ref == NULL) 2961 return B_BAD_VALUE; 2962 2963 void* data = NULL; 2964 ssize_t size = 0; 2965 status_t error = FindData(name, B_REF_TYPE, index, 2966 (const void**)&data, &size); 2967 2968 if (error == B_OK) 2969 error = BPrivate::entry_ref_unflatten(ref, (char*)data, size); 2970 else 2971 *ref = entry_ref(); 2972 2973 return error; 2974 } 2975 2976 2977 status_t 2978 BMessage::FindMessage(const char* name, BMessage* message) const 2979 { 2980 return FindMessage(name, 0, message); 2981 } 2982 2983 2984 status_t 2985 BMessage::FindMessage(const char* name, int32 index, BMessage* message) const 2986 { 2987 if (message == NULL) 2988 return B_BAD_VALUE; 2989 2990 void* data = NULL; 2991 ssize_t size = 0; 2992 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2993 (const void**)&data, &size); 2994 2995 if (error == B_OK) 2996 error = message->Unflatten((const char*)data); 2997 else 2998 *message = BMessage(); 2999 3000 return error; 3001 } 3002 3003 3004 status_t 3005 BMessage::FindFlat(const char* name, BFlattenable* object) const 3006 { 3007 return FindFlat(name, 0, object); 3008 } 3009 3010 3011 status_t 3012 BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const 3013 { 3014 if (object == NULL) 3015 return B_BAD_VALUE; 3016 3017 void* data = NULL; 3018 ssize_t numBytes = 0; 3019 status_t error = FindData(name, object->TypeCode(), index, 3020 (const void**)&data, &numBytes); 3021 3022 if (error == B_OK) 3023 error = object->Unflatten(object->TypeCode(), data, numBytes); 3024 3025 return error; 3026 } 3027 3028 3029 status_t 3030 BMessage::FindData(const char* name, type_code type, const void** data, 3031 ssize_t* numBytes) const 3032 { 3033 return FindData(name, type, 0, data, numBytes); 3034 } 3035 3036 3037 status_t 3038 BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment) 3039 { 3040 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3041 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data)); 3042 } 3043 3044 3045 status_t 3046 BMessage::ReplaceAlignment(const char* name, int32 index, 3047 const BAlignment& alignment) 3048 { 3049 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3050 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data)); 3051 } 3052 3053 3054 status_t 3055 BMessage::ReplaceString(const char* name, const char* string) 3056 { 3057 if (string == NULL) 3058 return B_BAD_VALUE; 3059 3060 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 3061 } 3062 3063 3064 status_t 3065 BMessage::ReplaceString(const char* name, int32 index, const char* string) 3066 { 3067 if (string == NULL) 3068 return B_BAD_VALUE; 3069 3070 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 3071 } 3072 3073 3074 status_t 3075 BMessage::ReplaceString(const char* name, const BString& string) 3076 { 3077 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 3078 string.Length() + 1); 3079 } 3080 3081 3082 status_t 3083 BMessage::ReplaceString(const char* name, int32 index, const BString& string) 3084 { 3085 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 3086 string.Length() + 1); 3087 } 3088 3089 3090 status_t 3091 BMessage::ReplacePointer(const char* name, const void* pointer) 3092 { 3093 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 3094 } 3095 3096 3097 status_t 3098 BMessage::ReplacePointer(const char* name, int32 index, const void* pointer) 3099 { 3100 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 3101 } 3102 3103 3104 status_t 3105 BMessage::ReplaceMessenger(const char* name, BMessenger messenger) 3106 { 3107 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 3108 sizeof(BMessenger)); 3109 } 3110 3111 3112 status_t 3113 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger) 3114 { 3115 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 3116 sizeof(BMessenger)); 3117 } 3118 3119 3120 status_t 3121 BMessage::ReplaceRef(const char* name, const entry_ref* ref) 3122 { 3123 return ReplaceRef(name, 0, ref); 3124 } 3125 3126 3127 status_t 3128 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref) 3129 { 3130 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 3131 char buffer[size]; 3132 3133 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 3134 3135 if (error >= B_OK) 3136 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 3137 3138 return error; 3139 } 3140 3141 3142 status_t 3143 BMessage::ReplaceMessage(const char* name, const BMessage* message) 3144 { 3145 return ReplaceMessage(name, 0, message); 3146 } 3147 3148 3149 status_t 3150 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message) 3151 { 3152 if (message == NULL) 3153 return B_BAD_VALUE; 3154 3155 ssize_t size = message->FlattenedSize(); 3156 char buffer[size]; 3157 3158 status_t error = message->Flatten(buffer, size); 3159 3160 if (error >= B_OK) 3161 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 3162 3163 return error; 3164 } 3165 3166 3167 status_t 3168 BMessage::ReplaceFlat(const char* name, BFlattenable* object) 3169 { 3170 return ReplaceFlat(name, 0, object); 3171 } 3172 3173 3174 status_t 3175 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object) 3176 { 3177 if (object == NULL) 3178 return B_BAD_VALUE; 3179 3180 ssize_t size = object->FlattenedSize(); 3181 char buffer[size]; 3182 3183 status_t error = object->Flatten(buffer, size); 3184 3185 if (error >= B_OK) 3186 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 3187 3188 return error; 3189 } 3190 3191 3192 status_t 3193 BMessage::ReplaceData(const char* name, type_code type, const void* data, 3194 ssize_t numBytes) 3195 { 3196 return ReplaceData(name, type, 0, data, numBytes); 3197 } 3198 3199 3200 bool 3201 BMessage::HasFlat(const char* name, const BFlattenable* object) const 3202 { 3203 return HasFlat(name, 0, object); 3204 } 3205 3206 3207 bool 3208 BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object) 3209 const 3210 { 3211 return HasData(name, object->TypeCode(), index); 3212 } 3213 3214 3215 const char* 3216 BMessage::GetString(const char* name, const char* defaultValue) const 3217 { 3218 return GetString(name, 0, defaultValue); 3219 } 3220 3221 3222 const char* 3223 BMessage::GetString(const char* name, int32 index, 3224 const char* defaultValue) const 3225 { 3226 const char* value; 3227 if (FindString(name, index, &value) == B_OK) 3228 return value; 3229 3230 return defaultValue; 3231 } 3232 3233 3234 status_t 3235 BMessage::SetString(const char* name, const BString& value) 3236 { 3237 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1); 3238 } 3239 3240 3241 status_t 3242 BMessage::SetString(const char* name, const char* value) 3243 { 3244 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1); 3245 } 3246 3247 3248 status_t 3249 BMessage::SetData(const char* name, type_code type, const void* data, 3250 ssize_t numBytes) 3251 { 3252 if (numBytes <= 0 || data == NULL) 3253 return B_BAD_VALUE; 3254 3255 if (ReplaceData(name, type, data, numBytes) == B_OK) 3256 return B_OK; 3257 3258 return AddData(name, type, data, numBytes); 3259 } 3260