1 /* 2 * Copyright 2005-2017 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 return Find##typeName(name, 0, p); \ 2442 } \ 2443 \ 2444 \ 2445 status_t \ 2446 BMessage::Find##typeName(const char* name, int32 index, type* p) const \ 2447 { \ 2448 type* ptr = NULL; \ 2449 ssize_t bytes = 0; \ 2450 status_t error = B_OK; \ 2451 \ 2452 *p = type(); \ 2453 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \ 2454 \ 2455 if (error == B_OK) \ 2456 *p = *ptr; \ 2457 \ 2458 return error; \ 2459 } \ 2460 \ 2461 \ 2462 status_t \ 2463 BMessage::Replace##typeName(const char* name, type value) \ 2464 { \ 2465 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \ 2466 } \ 2467 \ 2468 \ 2469 status_t \ 2470 BMessage::Replace##typeName(const char* name, int32 index, type value) \ 2471 { \ 2472 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \ 2473 } \ 2474 \ 2475 \ 2476 bool \ 2477 BMessage::Has##typeName(const char* name, int32 index) const \ 2478 { \ 2479 return HasData(name, typeCode, index); \ 2480 } 2481 2482 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2483 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2484 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2485 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2486 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2487 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2488 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2489 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2490 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2491 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2492 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2493 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2494 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2495 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2496 DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE); 2497 2498 #undef DEFINE_FUNCTIONS 2499 2500 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2501 bool \ 2502 BMessage::Has##typeName(const char* name, int32 index) const \ 2503 { \ 2504 return HasData(name, typeCode, index); \ 2505 } 2506 2507 2508 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE); 2509 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2510 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2511 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2512 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2513 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2514 2515 #undef DEFINE_HAS_FUNCTION 2516 2517 2518 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2519 type \ 2520 BMessage::Find##typeName(const char* name, int32 index) const \ 2521 { \ 2522 type val = initialize; \ 2523 Find##typeName(name, index, &val); \ 2524 return val; \ 2525 } 2526 2527 2528 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2529 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2530 DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL); 2531 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2532 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2533 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2534 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2535 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2536 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2537 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2538 2539 #undef DEFINE_LAZY_FIND_FUNCTION 2540 2541 2542 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \ 2543 type \ 2544 BMessage::Get##typeName(const char* name, type defaultValue) const \ 2545 { \ 2546 return Get##typeName(name, 0, defaultValue); \ 2547 } \ 2548 \ 2549 \ 2550 type \ 2551 BMessage::Get##typeName(const char* name, int32 index, \ 2552 type defaultValue) const \ 2553 { \ 2554 type value; \ 2555 if (Find##typeName(name, index, &value) == B_OK) \ 2556 return value; \ 2557 \ 2558 return defaultValue; \ 2559 } \ 2560 \ 2561 \ 2562 status_t \ 2563 BMessage::Set##typeName(const char* name, type value) \ 2564 { \ 2565 return SetData(name, typeCode, &value, sizeof(type)); \ 2566 } \ 2567 2568 2569 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2570 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2571 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2572 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2573 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2574 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2575 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2576 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2577 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2578 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2579 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2580 DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE); 2581 2582 #undef DEFINE_SET_GET_FUNCTION 2583 2584 2585 const void* 2586 BMessage::GetPointer(const char* name, const void* defaultValue) const 2587 { 2588 return GetPointer(name, 0, defaultValue); 2589 } 2590 2591 2592 const void* 2593 BMessage::GetPointer(const char* name, int32 index, 2594 const void* defaultValue) const 2595 { 2596 void* value; 2597 if (FindPointer(name, index, &value) == B_OK) 2598 return value; 2599 2600 return defaultValue; 2601 } 2602 2603 2604 status_t 2605 BMessage::SetPointer(const char* name, const void* value) 2606 { 2607 return SetData(name, B_POINTER_TYPE, &value, sizeof(void*)); 2608 } 2609 2610 2611 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \ 2612 type \ 2613 BMessage::Get##typeName(const char* name, const type& defaultValue) const \ 2614 { \ 2615 return Get##typeName(name, 0, defaultValue); \ 2616 } \ 2617 \ 2618 \ 2619 type \ 2620 BMessage::Get##typeName(const char* name, int32 index, \ 2621 const type& defaultValue) const \ 2622 { \ 2623 type value; \ 2624 if (Find##typeName(name, index, &value) == B_OK) \ 2625 return value; \ 2626 \ 2627 return defaultValue; \ 2628 } \ 2629 \ 2630 \ 2631 status_t \ 2632 BMessage::Set##typeName(const char* name, const type& value) \ 2633 { \ 2634 return SetData(name, typeCode, &value, sizeof(type)); \ 2635 } \ 2636 2637 2638 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2639 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2640 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2641 2642 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS 2643 2644 2645 status_t 2646 BMessage::AddAlignment(const char* name, const BAlignment& alignment) 2647 { 2648 int32 data[2] = { alignment.horizontal, alignment.vertical }; 2649 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data)); 2650 } 2651 2652 2653 status_t 2654 BMessage::AddString(const char* name, const char* string) 2655 { 2656 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, 2657 false); 2658 } 2659 2660 2661 status_t 2662 BMessage::AddString(const char* name, const BString& string) 2663 { 2664 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, 2665 false); 2666 } 2667 2668 2669 status_t 2670 BMessage::AddStrings(const char* name, const BStringList& list) 2671 { 2672 int32 count = list.CountStrings(); 2673 for (int32 i = 0; i < count; i++) { 2674 status_t error = AddString(name, list.StringAt(i)); 2675 if (error != B_OK) 2676 return error; 2677 } 2678 2679 return B_OK; 2680 } 2681 2682 2683 status_t 2684 BMessage::AddPointer(const char* name, const void* pointer) 2685 { 2686 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2687 } 2688 2689 2690 status_t 2691 BMessage::AddMessenger(const char* name, BMessenger messenger) 2692 { 2693 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2694 } 2695 2696 2697 status_t 2698 BMessage::AddRef(const char* name, const entry_ref* ref) 2699 { 2700 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2701 char buffer[size]; 2702 2703 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2704 2705 if (error >= B_OK) 2706 error = AddData(name, B_REF_TYPE, buffer, size, false); 2707 2708 return error; 2709 } 2710 2711 2712 status_t 2713 BMessage::AddMessage(const char* name, const BMessage* message) 2714 { 2715 if (message == NULL) 2716 return B_BAD_VALUE; 2717 2718 // TODO: This and the following functions waste time by allocating and 2719 // copying an extra buffer. Functions can be added that return a direct 2720 // pointer into the message. 2721 2722 char stackBuffer[16384]; 2723 ssize_t size = message->FlattenedSize(); 2724 2725 char* buffer; 2726 if (size > (ssize_t)sizeof(stackBuffer)) { 2727 buffer = (char*)malloc(size); 2728 if (buffer == NULL) 2729 return B_NO_MEMORY; 2730 } else 2731 buffer = stackBuffer; 2732 2733 status_t error = message->Flatten(buffer, size); 2734 2735 if (error >= B_OK) 2736 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2737 2738 if (buffer != stackBuffer) 2739 free(buffer); 2740 2741 return error; 2742 } 2743 2744 2745 status_t 2746 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count) 2747 { 2748 return AddFlat(name, (const BFlattenable*)object, count); 2749 } 2750 2751 2752 status_t 2753 BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count) 2754 { 2755 if (object == NULL) 2756 return B_BAD_VALUE; 2757 2758 char stackBuffer[16384]; 2759 ssize_t size = object->FlattenedSize(); 2760 2761 char* buffer; 2762 if (size > (ssize_t)sizeof(stackBuffer)) { 2763 buffer = (char*)malloc(size); 2764 if (buffer == NULL) 2765 return B_NO_MEMORY; 2766 } else 2767 buffer = stackBuffer; 2768 2769 status_t error = object->Flatten(buffer, size); 2770 2771 if (error >= B_OK) 2772 error = AddData(name, object->TypeCode(), buffer, size, false); 2773 2774 if (buffer != stackBuffer) 2775 free(buffer); 2776 2777 return error; 2778 } 2779 2780 2781 status_t 2782 BMessage::Append(const BMessage& other) 2783 { 2784 field_header* field = other.fFields; 2785 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) { 2786 const char* name = (const char*)(other.fData + field->offset); 2787 const void* data = (const void*)(other.fData + field->offset 2788 + field->name_length); 2789 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 2790 size_t size = field->data_size / field->count; 2791 2792 for (uint32 j = 0; j < field->count; j++) { 2793 if (!isFixed) { 2794 size = *(uint32*)data; 2795 data = (const void*)((const char*)data + sizeof(uint32)); 2796 } 2797 2798 status_t status = AddData(name, field->type, data, size, 2799 isFixed, 1); 2800 if (status != B_OK) 2801 return status; 2802 2803 data = (const void*)((const char*)data + size); 2804 } 2805 } 2806 return B_OK; 2807 } 2808 2809 2810 status_t 2811 BMessage::FindAlignment(const char* name, BAlignment* alignment) const 2812 { 2813 return FindAlignment(name, 0, alignment); 2814 } 2815 2816 2817 status_t 2818 BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment) 2819 const 2820 { 2821 if (!alignment) 2822 return B_BAD_VALUE; 2823 2824 int32* data; 2825 ssize_t bytes; 2826 2827 status_t err = FindData(name, B_ALIGNMENT_TYPE, index, 2828 (const void**)&data, &bytes); 2829 2830 if (err == B_OK) { 2831 if (bytes != sizeof(int32[2])) 2832 return B_ERROR; 2833 2834 alignment->horizontal = (enum alignment)(*data); 2835 alignment->vertical = (vertical_alignment)*(data + 1); 2836 } 2837 2838 return err; 2839 } 2840 2841 2842 status_t 2843 BMessage::FindString(const char* name, const char** string) const 2844 { 2845 return FindString(name, 0, string); 2846 } 2847 2848 2849 status_t 2850 BMessage::FindString(const char* name, int32 index, const char** string) const 2851 { 2852 ssize_t bytes; 2853 return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes); 2854 } 2855 2856 2857 status_t 2858 BMessage::FindString(const char* name, BString* string) const 2859 { 2860 return FindString(name, 0, string); 2861 } 2862 2863 2864 status_t 2865 BMessage::FindString(const char* name, int32 index, BString* string) const 2866 { 2867 if (string == NULL) 2868 return B_BAD_VALUE; 2869 2870 const char* value; 2871 status_t error = FindString(name, index, &value); 2872 2873 // Find*() clobbers the object even on failure 2874 string->SetTo(value); 2875 return error; 2876 } 2877 2878 2879 status_t 2880 BMessage::FindStrings(const char* name, BStringList* list) const 2881 { 2882 if (list == NULL) 2883 return B_BAD_VALUE; 2884 2885 list->MakeEmpty(); 2886 2887 // get the number of items 2888 type_code type; 2889 int32 count; 2890 if (GetInfo(name, &type, &count) != B_OK) 2891 return B_NAME_NOT_FOUND; 2892 2893 if (type != B_STRING_TYPE) 2894 return B_BAD_DATA; 2895 2896 for (int32 i = 0; i < count; i++) { 2897 BString string; 2898 status_t error = FindString(name, i, &string); 2899 if (error != B_OK) 2900 return error; 2901 if (!list->Add(string)) 2902 return B_NO_MEMORY; 2903 } 2904 2905 return B_OK; 2906 } 2907 2908 2909 status_t 2910 BMessage::FindPointer(const char* name, void** pointer) const 2911 { 2912 return FindPointer(name, 0, pointer); 2913 } 2914 2915 2916 status_t 2917 BMessage::FindPointer(const char* name, int32 index, void** pointer) const 2918 { 2919 if (pointer == NULL) 2920 return B_BAD_VALUE; 2921 2922 void** data = NULL; 2923 ssize_t size = 0; 2924 status_t error = FindData(name, B_POINTER_TYPE, index, 2925 (const void**)&data, &size); 2926 2927 if (error == B_OK) 2928 *pointer = *data; 2929 else 2930 *pointer = NULL; 2931 2932 return error; 2933 } 2934 2935 2936 status_t 2937 BMessage::FindMessenger(const char* name, BMessenger* messenger) const 2938 { 2939 return FindMessenger(name, 0, messenger); 2940 } 2941 2942 2943 status_t 2944 BMessage::FindMessenger(const char* name, int32 index, 2945 BMessenger* messenger) const 2946 { 2947 if (messenger == NULL) 2948 return B_BAD_VALUE; 2949 2950 BMessenger* data = NULL; 2951 ssize_t size = 0; 2952 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2953 (const void**)&data, &size); 2954 2955 if (error == B_OK) 2956 *messenger = *data; 2957 else 2958 *messenger = BMessenger(); 2959 2960 return error; 2961 } 2962 2963 2964 status_t 2965 BMessage::FindRef(const char* name, entry_ref* ref) const 2966 { 2967 return FindRef(name, 0, ref); 2968 } 2969 2970 2971 status_t 2972 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const 2973 { 2974 if (ref == NULL) 2975 return B_BAD_VALUE; 2976 2977 void* data = NULL; 2978 ssize_t size = 0; 2979 status_t error = FindData(name, B_REF_TYPE, index, 2980 (const void**)&data, &size); 2981 2982 if (error == B_OK) 2983 error = BPrivate::entry_ref_unflatten(ref, (char*)data, size); 2984 else 2985 *ref = entry_ref(); 2986 2987 return error; 2988 } 2989 2990 2991 status_t 2992 BMessage::FindMessage(const char* name, BMessage* message) const 2993 { 2994 return FindMessage(name, 0, message); 2995 } 2996 2997 2998 status_t 2999 BMessage::FindMessage(const char* name, int32 index, BMessage* message) const 3000 { 3001 if (message == NULL) 3002 return B_BAD_VALUE; 3003 3004 void* data = NULL; 3005 ssize_t size = 0; 3006 status_t error = FindData(name, B_MESSAGE_TYPE, index, 3007 (const void**)&data, &size); 3008 3009 if (error == B_OK) 3010 error = message->Unflatten((const char*)data); 3011 else 3012 *message = BMessage(); 3013 3014 return error; 3015 } 3016 3017 3018 status_t 3019 BMessage::FindFlat(const char* name, BFlattenable* object) const 3020 { 3021 return FindFlat(name, 0, object); 3022 } 3023 3024 3025 status_t 3026 BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const 3027 { 3028 if (object == NULL) 3029 return B_BAD_VALUE; 3030 3031 void* data = NULL; 3032 ssize_t numBytes = 0; 3033 status_t error = FindData(name, object->TypeCode(), index, 3034 (const void**)&data, &numBytes); 3035 3036 if (error == B_OK) 3037 error = object->Unflatten(object->TypeCode(), data, numBytes); 3038 3039 return error; 3040 } 3041 3042 3043 status_t 3044 BMessage::FindData(const char* name, type_code type, const void** data, 3045 ssize_t* numBytes) const 3046 { 3047 return FindData(name, type, 0, data, numBytes); 3048 } 3049 3050 3051 status_t 3052 BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment) 3053 { 3054 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3055 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data)); 3056 } 3057 3058 3059 status_t 3060 BMessage::ReplaceAlignment(const char* name, int32 index, 3061 const BAlignment& alignment) 3062 { 3063 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3064 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data)); 3065 } 3066 3067 3068 status_t 3069 BMessage::ReplaceString(const char* name, const char* string) 3070 { 3071 if (string == NULL) 3072 return B_BAD_VALUE; 3073 3074 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 3075 } 3076 3077 3078 status_t 3079 BMessage::ReplaceString(const char* name, int32 index, const char* string) 3080 { 3081 if (string == NULL) 3082 return B_BAD_VALUE; 3083 3084 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 3085 } 3086 3087 3088 status_t 3089 BMessage::ReplaceString(const char* name, const BString& string) 3090 { 3091 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 3092 string.Length() + 1); 3093 } 3094 3095 3096 status_t 3097 BMessage::ReplaceString(const char* name, int32 index, const BString& string) 3098 { 3099 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 3100 string.Length() + 1); 3101 } 3102 3103 3104 status_t 3105 BMessage::ReplacePointer(const char* name, const void* pointer) 3106 { 3107 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 3108 } 3109 3110 3111 status_t 3112 BMessage::ReplacePointer(const char* name, int32 index, const void* pointer) 3113 { 3114 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 3115 } 3116 3117 3118 status_t 3119 BMessage::ReplaceMessenger(const char* name, BMessenger messenger) 3120 { 3121 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 3122 sizeof(BMessenger)); 3123 } 3124 3125 3126 status_t 3127 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger) 3128 { 3129 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 3130 sizeof(BMessenger)); 3131 } 3132 3133 3134 status_t 3135 BMessage::ReplaceRef(const char* name, const entry_ref* ref) 3136 { 3137 return ReplaceRef(name, 0, ref); 3138 } 3139 3140 3141 status_t 3142 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref) 3143 { 3144 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 3145 char buffer[size]; 3146 3147 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 3148 3149 if (error >= B_OK) 3150 error = ReplaceData(name, B_REF_TYPE, index, buffer, size); 3151 3152 return error; 3153 } 3154 3155 3156 status_t 3157 BMessage::ReplaceMessage(const char* name, const BMessage* message) 3158 { 3159 return ReplaceMessage(name, 0, message); 3160 } 3161 3162 3163 status_t 3164 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message) 3165 { 3166 if (message == NULL) 3167 return B_BAD_VALUE; 3168 3169 ssize_t size = message->FlattenedSize(); 3170 char buffer[size]; 3171 3172 status_t error = message->Flatten(buffer, size); 3173 3174 if (error >= B_OK) 3175 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 3176 3177 return error; 3178 } 3179 3180 3181 status_t 3182 BMessage::ReplaceFlat(const char* name, BFlattenable* object) 3183 { 3184 return ReplaceFlat(name, 0, object); 3185 } 3186 3187 3188 status_t 3189 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object) 3190 { 3191 if (object == NULL) 3192 return B_BAD_VALUE; 3193 3194 ssize_t size = object->FlattenedSize(); 3195 char buffer[size]; 3196 3197 status_t error = object->Flatten(buffer, size); 3198 3199 if (error >= B_OK) 3200 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 3201 3202 return error; 3203 } 3204 3205 3206 status_t 3207 BMessage::ReplaceData(const char* name, type_code type, const void* data, 3208 ssize_t numBytes) 3209 { 3210 return ReplaceData(name, type, 0, data, numBytes); 3211 } 3212 3213 3214 bool 3215 BMessage::HasFlat(const char* name, const BFlattenable* object) const 3216 { 3217 return HasFlat(name, 0, object); 3218 } 3219 3220 3221 bool 3222 BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object) 3223 const 3224 { 3225 return HasData(name, object->TypeCode(), index); 3226 } 3227 3228 3229 const char* 3230 BMessage::GetString(const char* name, const char* defaultValue) const 3231 { 3232 return GetString(name, 0, defaultValue); 3233 } 3234 3235 3236 const char* 3237 BMessage::GetString(const char* name, int32 index, 3238 const char* defaultValue) const 3239 { 3240 const char* value; 3241 if (FindString(name, index, &value) == B_OK) 3242 return value; 3243 3244 return defaultValue; 3245 } 3246 3247 3248 status_t 3249 BMessage::SetString(const char* name, const BString& value) 3250 { 3251 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1, 3252 false); 3253 } 3254 3255 3256 status_t 3257 BMessage::SetString(const char* name, const char* value) 3258 { 3259 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false); 3260 } 3261 3262 3263 status_t 3264 BMessage::SetData(const char* name, type_code type, const void* data, 3265 ssize_t numBytes, bool fixedSize, int count) 3266 { 3267 if (numBytes <= 0 || data == NULL) 3268 return B_BAD_VALUE; 3269 3270 if (ReplaceData(name, type, data, numBytes) == B_OK) 3271 return B_OK; 3272 3273 return AddData(name, type, data, numBytes, fixedSize, count); 3274 } 3275