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