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