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