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