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