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 free(fData); 1372 fData = NULL; 1373 free(fFields); 1374 fFields = NULL; 1375 _InitHeader(); 1376 return result < 0 ? result : B_BAD_VALUE; 1377 } 1378 } 1379 } 1380 1381 return _ValidateMessage(); 1382 } 1383 1384 1385 status_t 1386 BMessage::AddSpecifier(const char* property) 1387 { 1388 DEBUG_FUNCTION_ENTER; 1389 BMessage message(B_DIRECT_SPECIFIER); 1390 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1391 if (result != B_OK) 1392 return result; 1393 1394 return AddSpecifier(&message); 1395 } 1396 1397 1398 status_t 1399 BMessage::AddSpecifier(const char* property, int32 index) 1400 { 1401 DEBUG_FUNCTION_ENTER; 1402 BMessage message(B_INDEX_SPECIFIER); 1403 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1404 if (result != B_OK) 1405 return result; 1406 1407 result = message.AddInt32("index", index); 1408 if (result != B_OK) 1409 return result; 1410 1411 return AddSpecifier(&message); 1412 } 1413 1414 1415 status_t 1416 BMessage::AddSpecifier(const char* property, int32 index, int32 range) 1417 { 1418 DEBUG_FUNCTION_ENTER; 1419 if (range < 0) 1420 return B_BAD_VALUE; 1421 1422 BMessage message(B_RANGE_SPECIFIER); 1423 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1424 if (result != B_OK) 1425 return result; 1426 1427 result = message.AddInt32("index", index); 1428 if (result != B_OK) 1429 return result; 1430 1431 result = message.AddInt32("range", range); 1432 if (result != B_OK) 1433 return result; 1434 1435 return AddSpecifier(&message); 1436 } 1437 1438 1439 status_t 1440 BMessage::AddSpecifier(const char* property, const char* name) 1441 { 1442 DEBUG_FUNCTION_ENTER; 1443 BMessage message(B_NAME_SPECIFIER); 1444 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1445 if (result != B_OK) 1446 return result; 1447 1448 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1449 if (result != B_OK) 1450 return result; 1451 1452 return AddSpecifier(&message); 1453 } 1454 1455 1456 status_t 1457 BMessage::AddSpecifier(const BMessage* specifier) 1458 { 1459 DEBUG_FUNCTION_ENTER; 1460 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1461 if (result != B_OK) 1462 return result; 1463 1464 fHeader->current_specifier++; 1465 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1466 return B_OK; 1467 } 1468 1469 1470 status_t 1471 BMessage::SetCurrentSpecifier(int32 index) 1472 { 1473 DEBUG_FUNCTION_ENTER; 1474 if (index < 0) 1475 return B_BAD_INDEX; 1476 1477 type_code type; 1478 int32 count; 1479 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1480 if (result != B_OK) 1481 return result; 1482 1483 if (index >= count) 1484 return B_BAD_INDEX; 1485 1486 fHeader->current_specifier = index; 1487 return B_OK; 1488 } 1489 1490 1491 status_t 1492 BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what, 1493 const char** property) const 1494 { 1495 DEBUG_FUNCTION_ENTER; 1496 if (fHeader == NULL) 1497 return B_NO_INIT; 1498 1499 if (index != NULL) 1500 *index = fHeader->current_specifier; 1501 1502 if (fHeader->current_specifier < 0 1503 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1504 return B_BAD_SCRIPT_SYNTAX; 1505 1506 if (specifier) { 1507 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1508 specifier) != B_OK) 1509 return B_BAD_SCRIPT_SYNTAX; 1510 1511 if (_what != NULL) 1512 *_what = specifier->what; 1513 1514 if (property) { 1515 if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK) 1516 return B_BAD_SCRIPT_SYNTAX; 1517 } 1518 } 1519 1520 return B_OK; 1521 } 1522 1523 1524 bool 1525 BMessage::HasSpecifiers() const 1526 { 1527 DEBUG_FUNCTION_ENTER; 1528 return fHeader != NULL 1529 && (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0; 1530 } 1531 1532 1533 status_t 1534 BMessage::PopSpecifier() 1535 { 1536 DEBUG_FUNCTION_ENTER; 1537 if (fHeader == NULL) 1538 return B_NO_INIT; 1539 1540 if (fHeader->current_specifier < 0 || 1541 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1542 return B_BAD_VALUE; 1543 1544 if (fHeader->current_specifier >= 0) 1545 fHeader->current_specifier--; 1546 1547 return B_OK; 1548 } 1549 1550 1551 void 1552 BMessage::_UpdateOffsets(uint32 offset, int32 change) 1553 { 1554 // Update the header to match the new position of the fields 1555 if (offset < fHeader->data_size) { 1556 field_header* field = fFields; 1557 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 1558 if (field->offset >= offset) 1559 field->offset += change; 1560 } 1561 } 1562 } 1563 1564 1565 status_t 1566 BMessage::_ResizeData(uint32 offset, int32 change) 1567 { 1568 if (change == 0) 1569 return B_OK; 1570 1571 /* optimize for the most usual case: appending data */ 1572 1573 if (change > 0) { 1574 // We need to make the field bigger 1575 // check if there is enough free space allocated 1576 if (fDataAvailable >= (uint32)change) { 1577 // In this case, we just need to move the data after the growing 1578 // field to get the space at the right place 1579 if (offset < fHeader->data_size) { 1580 memmove(fData + offset + change, fData + offset, 1581 fHeader->data_size - offset); 1582 } 1583 1584 _UpdateOffsets(offset, change); 1585 1586 fDataAvailable -= change; 1587 fHeader->data_size += change; 1588 return B_OK; 1589 } 1590 1591 // We need to grow the buffer. We try to optimize reallocations by 1592 // preallocating space for more fields. 1593 size_t size = fHeader->data_size * 2; 1594 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1595 size = max_c(size, fHeader->data_size + change); 1596 1597 uint8* newData = (uint8*)realloc(fData, size); 1598 if (size > 0 && newData == NULL) 1599 return B_NO_MEMORY; 1600 1601 fData = newData; 1602 if (offset < fHeader->data_size) { 1603 memmove(fData + offset + change, fData + offset, 1604 fHeader->data_size - offset); 1605 } 1606 1607 fHeader->data_size += change; 1608 fDataAvailable = size - fHeader->data_size; 1609 } else { 1610 ssize_t length = fHeader->data_size - offset + change; 1611 if (length > 0) 1612 memmove(fData + offset, fData + offset - change, length); 1613 1614 // change is negative 1615 fHeader->data_size += change; 1616 fDataAvailable -= change; 1617 1618 if (fDataAvailable > MAX_DATA_PREALLOCATION) { 1619 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1620 ssize_t size = fHeader->data_size + available; 1621 uint8* newData = (uint8*)realloc(fData, size); 1622 if (size > 0 && newData == NULL) { 1623 // this is strange, but not really fatal 1624 _UpdateOffsets(offset, change); 1625 return B_OK; 1626 } 1627 1628 fData = newData; 1629 fDataAvailable = available; 1630 } 1631 } 1632 1633 _UpdateOffsets(offset, change); 1634 return B_OK; 1635 } 1636 1637 1638 uint32 1639 BMessage::_HashName(const char* name) const 1640 { 1641 char ch; 1642 uint32 result = 0; 1643 1644 while ((ch = *name++) != 0) { 1645 result = (result << 7) ^ (result >> 24); 1646 result ^= ch; 1647 } 1648 1649 result ^= result << 12; 1650 return result; 1651 } 1652 1653 1654 status_t 1655 BMessage::_FindField(const char* name, type_code type, field_header** result) 1656 const 1657 { 1658 if (name == NULL) 1659 return B_BAD_VALUE; 1660 1661 if (fHeader == NULL) 1662 return B_NO_INIT; 1663 1664 if (fHeader->field_count == 0 || fFields == NULL || fData == NULL) 1665 return B_NAME_NOT_FOUND; 1666 1667 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1668 int32 nextField = fHeader->hash_table[hash]; 1669 1670 while (nextField >= 0) { 1671 field_header* field = &fFields[nextField]; 1672 if ((field->flags & FIELD_FLAG_VALID) == 0) 1673 break; 1674 1675 if (strncmp((const char*)(fData + field->offset), name, 1676 field->name_length) == 0) { 1677 if (type != B_ANY_TYPE && field->type != type) 1678 return B_BAD_TYPE; 1679 1680 *result = field; 1681 return B_OK; 1682 } 1683 1684 nextField = field->next_field; 1685 } 1686 1687 return B_NAME_NOT_FOUND; 1688 } 1689 1690 1691 status_t 1692 BMessage::_AddField(const char* name, type_code type, bool isFixedSize, 1693 field_header** result) 1694 { 1695 if (fHeader == NULL) 1696 return B_NO_INIT; 1697 1698 if (fFieldsAvailable <= 0) { 1699 uint32 count = fHeader->field_count * 2 + 1; 1700 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1701 1702 field_header* newFields = (field_header*)realloc(fFields, 1703 count * sizeof(field_header)); 1704 if (count > 0 && newFields == NULL) 1705 return B_NO_MEMORY; 1706 1707 fFields = newFields; 1708 fFieldsAvailable = count - fHeader->field_count; 1709 } 1710 1711 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1712 int32* nextField = &fHeader->hash_table[hash]; 1713 while (*nextField >= 0) 1714 nextField = &fFields[*nextField].next_field; 1715 *nextField = fHeader->field_count; 1716 1717 field_header* field = &fFields[fHeader->field_count]; 1718 field->type = type; 1719 field->count = 0; 1720 field->data_size = 0; 1721 field->next_field = -1; 1722 field->offset = fHeader->data_size; 1723 field->name_length = strlen(name) + 1; 1724 status_t status = _ResizeData(field->offset, field->name_length); 1725 if (status != B_OK) 1726 return status; 1727 1728 memcpy(fData + field->offset, name, field->name_length); 1729 field->flags = FIELD_FLAG_VALID; 1730 if (isFixedSize) 1731 field->flags |= FIELD_FLAG_FIXED_SIZE; 1732 1733 fFieldsAvailable--; 1734 fHeader->field_count++; 1735 *result = field; 1736 return B_OK; 1737 } 1738 1739 1740 status_t 1741 BMessage::_RemoveField(field_header* field) 1742 { 1743 status_t result = _ResizeData(field->offset, -(field->data_size 1744 + field->name_length)); 1745 if (result != B_OK) 1746 return result; 1747 1748 int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header); 1749 int32 nextField = field->next_field; 1750 if (nextField > index) 1751 nextField--; 1752 1753 int32* value = fHeader->hash_table; 1754 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1755 if (*value > index) 1756 *value -= 1; 1757 else if (*value == index) 1758 *value = nextField; 1759 } 1760 1761 field_header* other = fFields; 1762 for (uint32 i = 0; i < fHeader->field_count; i++, other++) { 1763 if (other->next_field > index) 1764 other->next_field--; 1765 else if (other->next_field == index) 1766 other->next_field = nextField; 1767 } 1768 1769 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header); 1770 memmove(fFields + index, fFields + index + 1, size); 1771 fHeader->field_count--; 1772 fFieldsAvailable++; 1773 1774 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) { 1775 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1776 size = (fHeader->field_count + available) * sizeof(field_header); 1777 field_header* newFields = (field_header*)realloc(fFields, size); 1778 if (size > 0 && newFields == NULL) { 1779 // this is strange, but not really fatal 1780 return B_OK; 1781 } 1782 1783 fFields = newFields; 1784 fFieldsAvailable = available; 1785 } 1786 1787 return B_OK; 1788 } 1789 1790 1791 status_t 1792 BMessage::AddData(const char* name, type_code type, const void* data, 1793 ssize_t numBytes, bool isFixedSize, int32 count) 1794 { 1795 // Note that the "count" argument is only a hint at how many items 1796 // the caller expects to add to this field. Since we do no item pre- 1797 // allocation, we ignore this argument. 1798 DEBUG_FUNCTION_ENTER; 1799 if (numBytes <= 0 || data == NULL) 1800 return B_BAD_VALUE; 1801 1802 if (fHeader == NULL) 1803 return B_NO_INIT; 1804 1805 status_t result; 1806 if (fHeader->message_area >= 0) { 1807 result = _CopyForWrite(); 1808 if (result != B_OK) 1809 return result; 1810 } 1811 1812 field_header* field = NULL; 1813 result = _FindField(name, type, &field); 1814 if (result == B_NAME_NOT_FOUND) 1815 result = _AddField(name, type, isFixedSize, &field); 1816 1817 if (result != B_OK) 1818 return result; 1819 1820 if (field == NULL) 1821 return B_ERROR; 1822 1823 uint32 offset = field->offset + field->name_length + field->data_size; 1824 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1825 if (field->count) { 1826 ssize_t size = field->data_size / field->count; 1827 if (size != numBytes) 1828 return B_BAD_VALUE; 1829 } 1830 1831 result = _ResizeData(offset, numBytes); 1832 if (result != B_OK) { 1833 if (field->count == 0) 1834 _RemoveField(field); 1835 return result; 1836 } 1837 1838 memcpy(fData + offset, data, numBytes); 1839 field->data_size += numBytes; 1840 } else { 1841 int32 change = numBytes + sizeof(uint32); 1842 result = _ResizeData(offset, change); 1843 if (result != B_OK) { 1844 if (field->count == 0) 1845 _RemoveField(field); 1846 return result; 1847 } 1848 1849 uint32 size = (uint32)numBytes; 1850 memcpy(fData + offset, &size, sizeof(uint32)); 1851 memcpy(fData + offset + sizeof(uint32), data, size); 1852 field->data_size += change; 1853 } 1854 1855 field->count++; 1856 return B_OK; 1857 } 1858 1859 1860 status_t 1861 BMessage::RemoveData(const char* name, int32 index) 1862 { 1863 DEBUG_FUNCTION_ENTER; 1864 if (index < 0) 1865 return B_BAD_INDEX; 1866 1867 if (fHeader == NULL) 1868 return B_NO_INIT; 1869 1870 status_t result; 1871 if (fHeader->message_area >= 0) { 1872 result = _CopyForWrite(); 1873 if (result != B_OK) 1874 return result; 1875 } 1876 1877 field_header* field = NULL; 1878 result = _FindField(name, B_ANY_TYPE, &field); 1879 if (result != B_OK) 1880 return result; 1881 1882 if ((uint32)index >= field->count) 1883 return B_BAD_INDEX; 1884 1885 if (field->count == 1) 1886 return _RemoveField(field); 1887 1888 uint32 offset = field->offset + field->name_length; 1889 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1890 ssize_t size = field->data_size / field->count; 1891 result = _ResizeData(offset + index * size, -size); 1892 if (result != B_OK) 1893 return result; 1894 1895 field->data_size -= size; 1896 } else { 1897 uint8* pointer = fData + offset; 1898 for (int32 i = 0; i < index; i++) { 1899 offset += *(uint32*)pointer + sizeof(uint32); 1900 pointer = fData + offset; 1901 } 1902 1903 size_t currentSize = *(uint32*)pointer + sizeof(uint32); 1904 result = _ResizeData(offset, -currentSize); 1905 if (result != B_OK) 1906 return result; 1907 1908 field->data_size -= currentSize; 1909 } 1910 1911 field->count--; 1912 return B_OK; 1913 } 1914 1915 1916 status_t 1917 BMessage::RemoveName(const char* name) 1918 { 1919 DEBUG_FUNCTION_ENTER; 1920 if (fHeader == NULL) 1921 return B_NO_INIT; 1922 1923 status_t result; 1924 if (fHeader->message_area >= 0) { 1925 result = _CopyForWrite(); 1926 if (result != B_OK) 1927 return result; 1928 } 1929 1930 field_header* field = NULL; 1931 result = _FindField(name, B_ANY_TYPE, &field); 1932 if (result != B_OK) 1933 return result; 1934 1935 return _RemoveField(field); 1936 } 1937 1938 1939 status_t 1940 BMessage::MakeEmpty() 1941 { 1942 DEBUG_FUNCTION_ENTER; 1943 _Clear(); 1944 return _InitHeader(); 1945 } 1946 1947 1948 status_t 1949 BMessage::FindData(const char* name, type_code type, int32 index, 1950 const void** data, ssize_t* numBytes) const 1951 { 1952 DEBUG_FUNCTION_ENTER; 1953 if (data == NULL) 1954 return B_BAD_VALUE; 1955 1956 *data = NULL; 1957 field_header* field = NULL; 1958 status_t result = _FindField(name, type, &field); 1959 if (result != B_OK) 1960 return result; 1961 1962 if (index < 0 || (uint32)index >= field->count) 1963 return B_BAD_INDEX; 1964 1965 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1966 size_t bytes = field->data_size / field->count; 1967 *data = fData + field->offset + field->name_length + index * bytes; 1968 if (numBytes != NULL) 1969 *numBytes = bytes; 1970 } else { 1971 uint8* pointer = fData + field->offset + field->name_length; 1972 for (int32 i = 0; i < index; i++) 1973 pointer += *(uint32*)pointer + sizeof(uint32); 1974 1975 *data = pointer + sizeof(uint32); 1976 if (numBytes != NULL) 1977 *numBytes = *(uint32*)pointer; 1978 } 1979 1980 return B_OK; 1981 } 1982 1983 1984 status_t 1985 BMessage::ReplaceData(const char* name, type_code type, int32 index, 1986 const void* data, ssize_t numBytes) 1987 { 1988 DEBUG_FUNCTION_ENTER; 1989 if (numBytes <= 0 || data == NULL) 1990 return B_BAD_VALUE; 1991 1992 status_t result; 1993 if (fHeader->message_area >= 0) { 1994 result = _CopyForWrite(); 1995 if (result != B_OK) 1996 return result; 1997 } 1998 1999 field_header* field = NULL; 2000 result = _FindField(name, type, &field); 2001 if (result != B_OK) 2002 return result; 2003 2004 if (index < 0 || (uint32)index >= field->count) 2005 return B_BAD_INDEX; 2006 2007 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 2008 ssize_t size = field->data_size / field->count; 2009 if (size != numBytes) 2010 return B_BAD_VALUE; 2011 2012 memcpy(fData + field->offset + field->name_length + index * size, data, 2013 size); 2014 } else { 2015 uint32 offset = field->offset + field->name_length; 2016 uint8* pointer = fData + offset; 2017 2018 for (int32 i = 0; i < index; i++) { 2019 offset += *(uint32*)pointer + sizeof(uint32); 2020 pointer = fData + offset; 2021 } 2022 2023 size_t currentSize = *(uint32*)pointer; 2024 int32 change = numBytes - currentSize; 2025 result = _ResizeData(offset, change); 2026 if (result != B_OK) 2027 return result; 2028 2029 uint32 newSize = (uint32)numBytes; 2030 memcpy(fData + offset, &newSize, sizeof(uint32)); 2031 memcpy(fData + offset + sizeof(uint32), data, newSize); 2032 field->data_size += change; 2033 } 2034 2035 return B_OK; 2036 } 2037 2038 2039 bool 2040 BMessage::HasData(const char* name, type_code type, int32 index) const 2041 { 2042 DEBUG_FUNCTION_ENTER; 2043 field_header* field = NULL; 2044 status_t result = _FindField(name, type, &field); 2045 if (result != B_OK) 2046 return false; 2047 2048 if (index < 0 || (uint32)index >= field->count) 2049 return false; 2050 2051 return true; 2052 } 2053 2054 2055 /* Static functions for cache initialization and cleanup */ 2056 void 2057 BMessage::_StaticInit() 2058 { 2059 DEBUG_FUNCTION_ENTER2; 2060 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2061 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2062 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2063 2064 sReplyPortInUse[0] = 0; 2065 sReplyPortInUse[1] = 0; 2066 sReplyPortInUse[2] = 0; 2067 2068 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 2069 } 2070 2071 2072 void 2073 BMessage::_StaticReInitForkedChild() 2074 { 2075 DEBUG_FUNCTION_ENTER2; 2076 2077 // overwrite the inherited ports with a set of our own 2078 sReplyPorts[0] = create_port(1, "tmp_rport0"); 2079 sReplyPorts[1] = create_port(1, "tmp_rport1"); 2080 sReplyPorts[2] = create_port(1, "tmp_rport2"); 2081 2082 sReplyPortInUse[0] = 0; 2083 sReplyPortInUse[1] = 0; 2084 sReplyPortInUse[2] = 0; 2085 } 2086 2087 2088 void 2089 BMessage::_StaticCleanup() 2090 { 2091 DEBUG_FUNCTION_ENTER2; 2092 delete_port(sReplyPorts[0]); 2093 sReplyPorts[0] = -1; 2094 delete_port(sReplyPorts[1]); 2095 sReplyPorts[1] = -1; 2096 delete_port(sReplyPorts[2]); 2097 sReplyPorts[2] = -1; 2098 } 2099 2100 2101 void 2102 BMessage::_StaticCacheCleanup() 2103 { 2104 DEBUG_FUNCTION_ENTER2; 2105 delete sMsgCache; 2106 sMsgCache = NULL; 2107 } 2108 2109 2110 int32 2111 BMessage::_StaticGetCachedReplyPort() 2112 { 2113 DEBUG_FUNCTION_ENTER2; 2114 int index = -1; 2115 for (int32 i = 0; i < sNumReplyPorts; i++) { 2116 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 2117 if (old == 0) { 2118 // This entry is free 2119 index = i; 2120 break; 2121 } else { 2122 // This entry is being used. 2123 atomic_add(&(sReplyPortInUse[i]), -1); 2124 } 2125 } 2126 2127 return index; 2128 } 2129 2130 2131 status_t 2132 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2133 bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const 2134 { 2135 DEBUG_FUNCTION_ENTER; 2136 ssize_t size = 0; 2137 char* buffer = NULL; 2138 message_header* header = NULL; 2139 status_t result = B_OK; 2140 2141 BPrivate::BDirectMessageTarget* direct = NULL; 2142 BMessage* copy = NULL; 2143 if (portOwner == BPrivate::current_team()) 2144 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct); 2145 2146 if (direct != NULL) { 2147 // We have a direct local message target - we can just enqueue the 2148 // message in its message queue. This will also prevent possible 2149 // deadlocks when the queue is full. 2150 copy = new BMessage(*this); 2151 if (copy != NULL) { 2152 header = copy->fHeader; 2153 header->flags = fHeader->flags; 2154 } else { 2155 direct->Release(); 2156 return B_NO_MEMORY; 2157 } 2158 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2159 } else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) { 2160 KMessage toMessage; 2161 result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage); 2162 if (result != B_OK) 2163 return result; 2164 2165 return toMessage.SendTo(port, token); 2166 } else if (fHeader->data_size > B_PAGE_SIZE * 10) { 2167 // ToDo: bind the above size to the max port message size 2168 // use message passing by area for such a large message 2169 result = _FlattenToArea(&header); 2170 if (result != B_OK) 2171 return result; 2172 2173 buffer = (char*)header; 2174 size = sizeof(message_header); 2175 2176 if (header->message_area >= 0) { 2177 team_id target = portOwner; 2178 if (target < 0) { 2179 port_info info; 2180 result = get_port_info(port, &info); 2181 if (result != B_OK) { 2182 free(header); 2183 return result; 2184 } 2185 target = info.team; 2186 } 2187 2188 void* address = NULL; 2189 area_id transfered = _kern_transfer_area(header->message_area, 2190 &address, B_ANY_ADDRESS, target); 2191 if (transfered < 0) { 2192 delete_area(header->message_area); 2193 free(header); 2194 return transfered; 2195 } 2196 2197 header->message_area = transfered; 2198 } 2199 #endif 2200 } else { 2201 size = FlattenedSize(); 2202 buffer = (char*)malloc(size); 2203 if (buffer == NULL) 2204 return B_NO_MEMORY; 2205 2206 result = Flatten(buffer, size); 2207 if (result != B_OK) { 2208 free(buffer); 2209 return result; 2210 } 2211 2212 header = (message_header*)buffer; 2213 } 2214 2215 if (!replyTo.IsValid()) { 2216 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 2217 fHeader->reply_port, fHeader->reply_target); 2218 2219 if (!replyTo.IsValid()) 2220 replyTo = be_app_messenger; 2221 } 2222 2223 BMessenger::Private replyToPrivate(replyTo); 2224 2225 if (replyRequired) { 2226 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 2227 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 2228 } 2229 2230 header->target = token; 2231 header->reply_team = replyToPrivate.Team(); 2232 header->reply_port = replyToPrivate.Port(); 2233 header->reply_target = replyToPrivate.Token(); 2234 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2235 2236 if (direct == NULL) { 2237 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2238 "message: '%c%c%c%c'", portOwner, port, token, 2239 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2240 2241 do { 2242 result = write_port_etc(port, kPortMessageCode, (void*)buffer, 2243 size, B_RELATIVE_TIMEOUT, timeout); 2244 } while (result == B_INTERRUPTED); 2245 } 2246 2247 if (result == B_OK && IsSourceWaiting()) { 2248 // the forwarded message will handle the reply - we must not do 2249 // this anymore 2250 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2251 } 2252 2253 // we need to do this last because it is possible our 2254 // message might be destroyed after it's enqueued in the 2255 // target looper. Thus we don't want to do any ops that depend on 2256 // members of this after the enqueue. 2257 if (direct != NULL) { 2258 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2259 "message: '%c%c%c%c'", port, token, 2260 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2261 2262 // this is a local message transmission 2263 direct->AddMessage(copy); 2264 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2265 // there is currently no message waiting, and we need to wakeup the 2266 // looper 2267 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2268 } 2269 direct->Release(); 2270 } 2271 2272 free(buffer); 2273 return result; 2274 } 2275 2276 2277 // Sends a message and waits synchronously for a reply. 2278 status_t 2279 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2280 BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2281 { 2282 if (IsSourceWaiting()) { 2283 // we can't forward this message synchronously when it's already 2284 // waiting for a reply 2285 return B_ERROR; 2286 } 2287 2288 DEBUG_FUNCTION_ENTER; 2289 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2290 port_id replyPort = B_BAD_PORT_ID; 2291 status_t result = B_OK; 2292 2293 if (cachedReplyPort < 0) { 2294 // All the cached reply ports are in use; create a new one 2295 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2296 if (replyPort < 0) 2297 return replyPort; 2298 } else { 2299 assert(cachedReplyPort < sNumReplyPorts); 2300 replyPort = sReplyPorts[cachedReplyPort]; 2301 } 2302 2303 bool recreateCachedPort = false; 2304 2305 team_id team = B_BAD_TEAM_ID; 2306 if (be_app != NULL) 2307 team = be_app->Team(); 2308 else { 2309 port_info portInfo; 2310 result = get_port_info(replyPort, &portInfo); 2311 if (result != B_OK) 2312 goto error; 2313 2314 team = portInfo.team; 2315 } 2316 2317 result = set_port_owner(replyPort, portOwner); 2318 if (result != B_OK) 2319 goto error; 2320 2321 // tests if the queue of the reply port is really empty 2322 #if 0 2323 port_info portInfo; 2324 if (get_port_info(replyPort, &portInfo) == B_OK 2325 && portInfo.queue_count > 0) { 2326 debugger("reply port not empty!"); 2327 printf(" reply port not empty! %ld message(s) in queue\n", 2328 portInfo.queue_count); 2329 2330 // fetch and print the messages 2331 for (int32 i = 0; i < portInfo.queue_count; i++) { 2332 char buffer[1024]; 2333 int32 code; 2334 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2335 if (size < 0) { 2336 printf("failed to read message from reply port\n"); 2337 continue; 2338 } 2339 if (size >= (ssize_t)sizeof(buffer)) { 2340 printf("message from reply port too big\n"); 2341 continue; 2342 } 2343 2344 BMemoryIO stream(buffer, size); 2345 BMessage reply; 2346 if (reply.Unflatten(&stream) != B_OK) { 2347 printf("failed to unflatten message from reply port\n"); 2348 continue; 2349 } 2350 2351 printf("message %ld from reply port:\n", i); 2352 reply.PrintToStream(); 2353 } 2354 } 2355 #endif 2356 2357 { 2358 BMessenger replyTarget; 2359 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2360 B_PREFERRED_TOKEN); 2361 // TODO: replying could also use a BDirectMessageTarget like mechanism 2362 // for local targets 2363 result = _SendMessage(port, -1, token, sendTimeout, true, 2364 replyTarget); 2365 } 2366 2367 if (result != B_OK) 2368 goto error; 2369 2370 int32 code; 2371 result = handle_reply(replyPort, &code, replyTimeout, reply); 2372 if (result != B_OK && cachedReplyPort >= 0) { 2373 delete_port(replyPort); 2374 recreateCachedPort = true; 2375 } 2376 2377 error: 2378 if (cachedReplyPort >= 0) { 2379 // Reclaim ownership of cached port, if possible 2380 if (!recreateCachedPort && set_port_owner(replyPort, team) == B_OK) { 2381 // Flag as available 2382 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2383 } else 2384 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2385 2386 return result; 2387 } 2388 2389 delete_port(replyPort); 2390 return result; 2391 } 2392 2393 2394 status_t 2395 BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port, 2396 int32 token, bigtime_t timeout) 2397 { 2398 DEBUG_FUNCTION_ENTER2; 2399 if (data == NULL) 2400 return B_BAD_VALUE; 2401 2402 uint32 magic = *(uint32*)data; 2403 2404 if (magic == MESSAGE_FORMAT_HAIKU 2405 || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2406 message_header* header = (message_header*)data; 2407 header->target = token; 2408 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2409 } else if (magic == MESSAGE_FORMAT_R5) { 2410 uint8* header = (uint8*)data; 2411 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2412 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2413 + sizeof(uint8) /* flags */; 2414 *(int32*)header = token; 2415 } else if (((KMessage::Header*)data)->magic 2416 == KMessage::kMessageHeaderMagic) { 2417 KMessage::Header* header = (KMessage::Header*)data; 2418 header->targetToken = token; 2419 } else { 2420 return B_NOT_A_MESSAGE; 2421 } 2422 2423 // send the message 2424 status_t result; 2425 2426 do { 2427 result = write_port_etc(port, kPortMessageCode, data, size, 2428 B_RELATIVE_TIMEOUT, timeout); 2429 } while (result == B_INTERRUPTED); 2430 2431 return result; 2432 } 2433 2434 2435 void BMessage::_ReservedMessage1() {} 2436 void BMessage::_ReservedMessage2() {} 2437 void BMessage::_ReservedMessage3() {} 2438 2439 2440 // #pragma mark - Macro definitions for data access methods 2441 2442 2443 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2444 2445 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2446 status_t \ 2447 BMessage::Add##typeName(const char* name, type val) \ 2448 { \ 2449 return AddData(name, typeCode, &val, sizeof(type), true); \ 2450 } \ 2451 \ 2452 \ 2453 status_t \ 2454 BMessage::Find##typeName(const char* name, type* p) const \ 2455 { \ 2456 return Find##typeName(name, 0, p); \ 2457 } \ 2458 \ 2459 \ 2460 status_t \ 2461 BMessage::Find##typeName(const char* name, int32 index, type* p) const \ 2462 { \ 2463 type* ptr = NULL; \ 2464 ssize_t bytes = 0; \ 2465 status_t error = B_OK; \ 2466 \ 2467 *p = type(); \ 2468 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \ 2469 \ 2470 if (error == B_OK) \ 2471 memcpy((void *)p, ptr, sizeof(type)); \ 2472 \ 2473 return error; \ 2474 } \ 2475 \ 2476 \ 2477 status_t \ 2478 BMessage::Replace##typeName(const char* name, type value) \ 2479 { \ 2480 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \ 2481 } \ 2482 \ 2483 \ 2484 status_t \ 2485 BMessage::Replace##typeName(const char* name, int32 index, type value) \ 2486 { \ 2487 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \ 2488 } \ 2489 \ 2490 \ 2491 bool \ 2492 BMessage::Has##typeName(const char* name, int32 index) const \ 2493 { \ 2494 return HasData(name, typeCode, index); \ 2495 } 2496 2497 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2498 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2499 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2500 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2501 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2502 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2503 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2504 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2505 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2506 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2507 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2508 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2509 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2510 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2511 DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE); 2512 2513 #undef DEFINE_FUNCTIONS 2514 2515 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2516 bool \ 2517 BMessage::Has##typeName(const char* name, int32 index) const \ 2518 { \ 2519 return HasData(name, typeCode, index); \ 2520 } 2521 2522 2523 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE); 2524 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2525 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2526 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2527 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2528 DEFINE_HAS_FUNCTION(NodeRef, B_NODE_REF_TYPE); 2529 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2530 2531 #undef DEFINE_HAS_FUNCTION 2532 2533 2534 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2535 type \ 2536 BMessage::Find##typeName(const char* name, int32 index) const \ 2537 { \ 2538 type val = initialize; \ 2539 Find##typeName(name, index, &val); \ 2540 return val; \ 2541 } 2542 2543 2544 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2545 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2546 DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL); 2547 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2548 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2549 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2550 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2551 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2552 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2553 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2554 2555 #undef DEFINE_LAZY_FIND_FUNCTION 2556 2557 2558 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \ 2559 type \ 2560 BMessage::Get##typeName(const char* name, type defaultValue) const \ 2561 { \ 2562 return Get##typeName(name, 0, defaultValue); \ 2563 } \ 2564 \ 2565 \ 2566 type \ 2567 BMessage::Get##typeName(const char* name, int32 index, \ 2568 type defaultValue) const \ 2569 { \ 2570 type value; \ 2571 if (Find##typeName(name, index, &value) == B_OK) \ 2572 return value; \ 2573 \ 2574 return defaultValue; \ 2575 } \ 2576 \ 2577 \ 2578 status_t \ 2579 BMessage::Set##typeName(const char* name, type value) \ 2580 { \ 2581 return SetData(name, typeCode, &value, sizeof(type)); \ 2582 } \ 2583 2584 2585 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2586 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2587 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2588 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2589 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2590 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2591 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2592 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2593 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2594 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2595 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2596 DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE); 2597 2598 #undef DEFINE_SET_GET_FUNCTION 2599 2600 2601 const void* 2602 BMessage::GetPointer(const char* name, const void* defaultValue) const 2603 { 2604 return GetPointer(name, 0, defaultValue); 2605 } 2606 2607 2608 const void* 2609 BMessage::GetPointer(const char* name, int32 index, 2610 const void* defaultValue) const 2611 { 2612 void* value; 2613 if (FindPointer(name, index, &value) == B_OK) 2614 return value; 2615 2616 return defaultValue; 2617 } 2618 2619 2620 status_t 2621 BMessage::SetPointer(const char* name, const void* value) 2622 { 2623 return SetData(name, B_POINTER_TYPE, &value, sizeof(void*)); 2624 } 2625 2626 2627 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \ 2628 type \ 2629 BMessage::Get##typeName(const char* name, const type& defaultValue) const \ 2630 { \ 2631 return Get##typeName(name, 0, defaultValue); \ 2632 } \ 2633 \ 2634 \ 2635 type \ 2636 BMessage::Get##typeName(const char* name, int32 index, \ 2637 const type& defaultValue) const \ 2638 { \ 2639 type value; \ 2640 if (Find##typeName(name, index, &value) == B_OK) \ 2641 return value; \ 2642 \ 2643 return defaultValue; \ 2644 } \ 2645 \ 2646 \ 2647 status_t \ 2648 BMessage::Set##typeName(const char* name, const type& value) \ 2649 { \ 2650 return SetData(name, typeCode, &value, sizeof(type)); \ 2651 } \ 2652 2653 2654 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2655 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2656 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE); 2657 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BAlignment, Alignment, B_ALIGNMENT_TYPE); 2658 2659 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS 2660 2661 2662 status_t 2663 BMessage::AddAlignment(const char* name, const BAlignment& alignment) 2664 { 2665 int32 data[2] = { alignment.horizontal, alignment.vertical }; 2666 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data)); 2667 } 2668 2669 2670 status_t 2671 BMessage::AddString(const char* name, const char* string) 2672 { 2673 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, 2674 false); 2675 } 2676 2677 2678 status_t 2679 BMessage::AddString(const char* name, const BString& string) 2680 { 2681 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, 2682 false); 2683 } 2684 2685 2686 status_t 2687 BMessage::AddStrings(const char* name, const BStringList& list) 2688 { 2689 int32 count = list.CountStrings(); 2690 for (int32 i = 0; i < count; i++) { 2691 status_t error = AddString(name, list.StringAt(i)); 2692 if (error != B_OK) 2693 return error; 2694 } 2695 2696 return B_OK; 2697 } 2698 2699 2700 status_t 2701 BMessage::AddPointer(const char* name, const void* pointer) 2702 { 2703 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2704 } 2705 2706 2707 status_t 2708 BMessage::AddMessenger(const char* name, BMessenger messenger) 2709 { 2710 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2711 } 2712 2713 2714 status_t 2715 BMessage::AddRef(const char* name, const entry_ref* ref) 2716 { 2717 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2718 char buffer[size]; 2719 2720 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2721 2722 if (error >= B_OK) 2723 error = AddData(name, B_REF_TYPE, buffer, size, false); 2724 2725 return error; 2726 } 2727 2728 2729 status_t 2730 BMessage::AddNodeRef(const char* name, const node_ref* ref) 2731 { 2732 size_t size = sizeof(node_ref); 2733 char buffer[size]; 2734 2735 status_t error = BPrivate::node_ref_flatten(buffer, &size, ref); 2736 2737 if (error >= B_OK) 2738 error = AddData(name, B_NODE_REF_TYPE, buffer, size, false); 2739 2740 return error; 2741 } 2742 2743 2744 status_t 2745 BMessage::AddMessage(const char* name, const BMessage* message) 2746 { 2747 if (message == NULL) 2748 return B_BAD_VALUE; 2749 2750 // TODO: This and the following functions waste time by allocating and 2751 // copying an extra buffer. Functions can be added that return a direct 2752 // pointer into the message. 2753 2754 char stackBuffer[16384]; 2755 ssize_t size = message->FlattenedSize(); 2756 2757 char* buffer; 2758 if (size > (ssize_t)sizeof(stackBuffer)) { 2759 buffer = (char*)malloc(size); 2760 if (buffer == NULL) 2761 return B_NO_MEMORY; 2762 } else 2763 buffer = stackBuffer; 2764 2765 status_t error = message->Flatten(buffer, size); 2766 2767 if (error >= B_OK) 2768 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2769 2770 if (buffer != stackBuffer) 2771 free(buffer); 2772 2773 return error; 2774 } 2775 2776 2777 status_t 2778 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count) 2779 { 2780 return AddFlat(name, (const BFlattenable*)object, count); 2781 } 2782 2783 2784 status_t 2785 BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count) 2786 { 2787 if (object == NULL) 2788 return B_BAD_VALUE; 2789 2790 char stackBuffer[16384]; 2791 ssize_t size = object->FlattenedSize(); 2792 2793 char* buffer; 2794 if (size > (ssize_t)sizeof(stackBuffer)) { 2795 buffer = (char*)malloc(size); 2796 if (buffer == NULL) 2797 return B_NO_MEMORY; 2798 } else 2799 buffer = stackBuffer; 2800 2801 status_t error = object->Flatten(buffer, size); 2802 2803 if (error >= B_OK) 2804 error = AddData(name, object->TypeCode(), buffer, size, false); 2805 2806 if (buffer != stackBuffer) 2807 free(buffer); 2808 2809 return error; 2810 } 2811 2812 2813 status_t 2814 BMessage::Append(const BMessage& other) 2815 { 2816 field_header* field = other.fFields; 2817 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) { 2818 const char* name = (const char*)(other.fData + field->offset); 2819 const void* data = (const void*)(other.fData + field->offset 2820 + field->name_length); 2821 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 2822 size_t size = field->data_size / field->count; 2823 2824 for (uint32 j = 0; j < field->count; j++) { 2825 if (!isFixed) { 2826 size = *(uint32*)data; 2827 data = (const void*)((const char*)data + sizeof(uint32)); 2828 } 2829 2830 status_t status = AddData(name, field->type, data, size, 2831 isFixed, 1); 2832 if (status != B_OK) 2833 return status; 2834 2835 data = (const void*)((const char*)data + size); 2836 } 2837 } 2838 return B_OK; 2839 } 2840 2841 2842 status_t 2843 BMessage::FindAlignment(const char* name, BAlignment* alignment) const 2844 { 2845 return FindAlignment(name, 0, alignment); 2846 } 2847 2848 2849 status_t 2850 BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment) 2851 const 2852 { 2853 if (!alignment) 2854 return B_BAD_VALUE; 2855 2856 int32* data; 2857 ssize_t bytes; 2858 2859 status_t err = FindData(name, B_ALIGNMENT_TYPE, index, 2860 (const void**)&data, &bytes); 2861 2862 if (err == B_OK) { 2863 if (bytes != sizeof(int32[2])) 2864 return B_ERROR; 2865 2866 alignment->horizontal = (enum alignment)(*data); 2867 alignment->vertical = (vertical_alignment)*(data + 1); 2868 } 2869 2870 return err; 2871 } 2872 2873 2874 status_t 2875 BMessage::FindString(const char* name, const char** string) const 2876 { 2877 return FindString(name, 0, string); 2878 } 2879 2880 2881 status_t 2882 BMessage::FindString(const char* name, int32 index, const char** string) const 2883 { 2884 ssize_t bytes; 2885 return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes); 2886 } 2887 2888 2889 status_t 2890 BMessage::FindString(const char* name, BString* string) const 2891 { 2892 return FindString(name, 0, string); 2893 } 2894 2895 2896 status_t 2897 BMessage::FindString(const char* name, int32 index, BString* string) const 2898 { 2899 if (string == NULL) 2900 return B_BAD_VALUE; 2901 2902 const char* value; 2903 status_t error = FindString(name, index, &value); 2904 2905 // Find*() clobbers the object even on failure 2906 string->SetTo(value); 2907 return error; 2908 } 2909 2910 2911 status_t 2912 BMessage::FindStrings(const char* name, BStringList* list) const 2913 { 2914 if (list == NULL) 2915 return B_BAD_VALUE; 2916 2917 list->MakeEmpty(); 2918 2919 // get the number of items 2920 type_code type; 2921 int32 count; 2922 if (GetInfo(name, &type, &count) != B_OK) 2923 return B_NAME_NOT_FOUND; 2924 2925 if (type != B_STRING_TYPE) 2926 return B_BAD_DATA; 2927 2928 for (int32 i = 0; i < count; i++) { 2929 BString string; 2930 status_t error = FindString(name, i, &string); 2931 if (error != B_OK) 2932 return error; 2933 if (!list->Add(string)) 2934 return B_NO_MEMORY; 2935 } 2936 2937 return B_OK; 2938 } 2939 2940 2941 status_t 2942 BMessage::FindPointer(const char* name, void** pointer) const 2943 { 2944 return FindPointer(name, 0, pointer); 2945 } 2946 2947 2948 status_t 2949 BMessage::FindPointer(const char* name, int32 index, void** pointer) const 2950 { 2951 if (pointer == NULL) 2952 return B_BAD_VALUE; 2953 2954 void** data = NULL; 2955 ssize_t size = 0; 2956 status_t error = FindData(name, B_POINTER_TYPE, index, 2957 (const void**)&data, &size); 2958 2959 if (error == B_OK) 2960 *pointer = *data; 2961 else 2962 *pointer = NULL; 2963 2964 return error; 2965 } 2966 2967 2968 status_t 2969 BMessage::FindMessenger(const char* name, BMessenger* messenger) const 2970 { 2971 return FindMessenger(name, 0, messenger); 2972 } 2973 2974 2975 status_t 2976 BMessage::FindMessenger(const char* name, int32 index, 2977 BMessenger* messenger) const 2978 { 2979 if (messenger == NULL) 2980 return B_BAD_VALUE; 2981 2982 BMessenger* data = NULL; 2983 ssize_t size = 0; 2984 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2985 (const void**)&data, &size); 2986 2987 if (error == B_OK) 2988 *messenger = *data; 2989 else 2990 *messenger = BMessenger(); 2991 2992 return error; 2993 } 2994 2995 2996 status_t 2997 BMessage::FindRef(const char* name, entry_ref* ref) const 2998 { 2999 return FindRef(name, 0, ref); 3000 } 3001 3002 3003 status_t 3004 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const 3005 { 3006 if (ref == NULL) 3007 return B_BAD_VALUE; 3008 3009 void* data = NULL; 3010 ssize_t size = 0; 3011 status_t error = FindData(name, B_REF_TYPE, index, 3012 (const void**)&data, &size); 3013 3014 if (error == B_OK) 3015 error = BPrivate::entry_ref_unflatten(ref, (char*)data, size); 3016 else 3017 *ref = entry_ref(); 3018 3019 return error; 3020 } 3021 3022 3023 status_t 3024 BMessage::FindNodeRef(const char* name, node_ref* ref) const 3025 { 3026 return FindNodeRef(name, 0, ref); 3027 } 3028 3029 3030 status_t 3031 BMessage::FindNodeRef(const char* name, int32 index, node_ref* ref) const 3032 { 3033 if (ref == NULL) 3034 return B_BAD_VALUE; 3035 3036 void* data = NULL; 3037 ssize_t size = 0; 3038 status_t error = FindData(name, B_NODE_REF_TYPE, index, 3039 (const void**)&data, &size); 3040 3041 if (error == B_OK) 3042 error = BPrivate::node_ref_unflatten(ref, (char*)data, size); 3043 else 3044 *ref = node_ref(); 3045 3046 return error; 3047 } 3048 3049 3050 status_t 3051 BMessage::FindMessage(const char* name, BMessage* message) const 3052 { 3053 return FindMessage(name, 0, message); 3054 } 3055 3056 3057 status_t 3058 BMessage::FindMessage(const char* name, int32 index, BMessage* message) const 3059 { 3060 if (message == NULL) 3061 return B_BAD_VALUE; 3062 3063 void* data = NULL; 3064 ssize_t size = 0; 3065 status_t error = FindData(name, B_MESSAGE_TYPE, index, 3066 (const void**)&data, &size); 3067 3068 if (error == B_OK) 3069 error = message->Unflatten((const char*)data); 3070 else 3071 *message = BMessage(); 3072 3073 return error; 3074 } 3075 3076 3077 status_t 3078 BMessage::FindFlat(const char* name, BFlattenable* object) const 3079 { 3080 return FindFlat(name, 0, object); 3081 } 3082 3083 3084 status_t 3085 BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const 3086 { 3087 if (object == NULL) 3088 return B_BAD_VALUE; 3089 3090 void* data = NULL; 3091 ssize_t numBytes = 0; 3092 status_t error = FindData(name, object->TypeCode(), index, 3093 (const void**)&data, &numBytes); 3094 3095 if (error == B_OK) 3096 error = object->Unflatten(object->TypeCode(), data, numBytes); 3097 3098 return error; 3099 } 3100 3101 3102 status_t 3103 BMessage::FindData(const char* name, type_code type, const void** data, 3104 ssize_t* numBytes) const 3105 { 3106 return FindData(name, type, 0, data, numBytes); 3107 } 3108 3109 3110 status_t 3111 BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment) 3112 { 3113 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3114 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data)); 3115 } 3116 3117 3118 status_t 3119 BMessage::ReplaceAlignment(const char* name, int32 index, 3120 const BAlignment& alignment) 3121 { 3122 int32 data[2] = {alignment.horizontal, alignment.vertical}; 3123 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data)); 3124 } 3125 3126 3127 status_t 3128 BMessage::ReplaceString(const char* name, const char* string) 3129 { 3130 if (string == NULL) 3131 return B_BAD_VALUE; 3132 3133 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 3134 } 3135 3136 3137 status_t 3138 BMessage::ReplaceString(const char* name, int32 index, const char* string) 3139 { 3140 if (string == NULL) 3141 return B_BAD_VALUE; 3142 3143 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 3144 } 3145 3146 3147 status_t 3148 BMessage::ReplaceString(const char* name, const BString& string) 3149 { 3150 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 3151 string.Length() + 1); 3152 } 3153 3154 3155 status_t 3156 BMessage::ReplaceString(const char* name, int32 index, const BString& string) 3157 { 3158 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 3159 string.Length() + 1); 3160 } 3161 3162 3163 status_t 3164 BMessage::ReplacePointer(const char* name, const void* pointer) 3165 { 3166 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 3167 } 3168 3169 3170 status_t 3171 BMessage::ReplacePointer(const char* name, int32 index, const void* pointer) 3172 { 3173 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 3174 } 3175 3176 3177 status_t 3178 BMessage::ReplaceMessenger(const char* name, BMessenger messenger) 3179 { 3180 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 3181 sizeof(BMessenger)); 3182 } 3183 3184 3185 status_t 3186 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger) 3187 { 3188 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 3189 sizeof(BMessenger)); 3190 } 3191 3192 3193 status_t 3194 BMessage::ReplaceRef(const char* name, const entry_ref* ref) 3195 { 3196 return ReplaceRef(name, 0, ref); 3197 } 3198 3199 3200 status_t 3201 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref) 3202 { 3203 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 3204 char buffer[size]; 3205 3206 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 3207 3208 if (error >= B_OK) 3209 error = ReplaceData(name, B_REF_TYPE, index, buffer, size); 3210 3211 return error; 3212 } 3213 3214 3215 status_t 3216 BMessage::ReplaceNodeRef(const char* name, const node_ref* ref) 3217 { 3218 return ReplaceNodeRef(name, 0, ref); 3219 } 3220 3221 3222 status_t 3223 BMessage::ReplaceNodeRef(const char* name, int32 index, const node_ref* ref) 3224 { 3225 size_t size = sizeof(node_ref) + B_PATH_NAME_LENGTH; 3226 char buffer[size]; 3227 3228 status_t error = BPrivate::node_ref_flatten(buffer, &size, ref); 3229 3230 if (error >= B_OK) 3231 error = ReplaceData(name, B_NODE_REF_TYPE, index, buffer, size); 3232 3233 return error; 3234 } 3235 3236 3237 status_t 3238 BMessage::ReplaceMessage(const char* name, const BMessage* message) 3239 { 3240 return ReplaceMessage(name, 0, message); 3241 } 3242 3243 3244 status_t 3245 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message) 3246 { 3247 if (message == NULL) 3248 return B_BAD_VALUE; 3249 3250 ssize_t size = message->FlattenedSize(); 3251 if (size < 0) 3252 return B_BAD_VALUE; 3253 3254 char buffer[size]; 3255 3256 status_t error = message->Flatten(buffer, size); 3257 3258 if (error >= B_OK) 3259 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 3260 3261 return error; 3262 } 3263 3264 3265 status_t 3266 BMessage::ReplaceFlat(const char* name, BFlattenable* object) 3267 { 3268 return ReplaceFlat(name, 0, object); 3269 } 3270 3271 3272 status_t 3273 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object) 3274 { 3275 if (object == NULL) 3276 return B_BAD_VALUE; 3277 3278 ssize_t size = object->FlattenedSize(); 3279 if (size < 0) 3280 return B_BAD_VALUE; 3281 3282 char buffer[size]; 3283 3284 status_t error = object->Flatten(buffer, size); 3285 3286 if (error >= B_OK) 3287 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 3288 3289 return error; 3290 } 3291 3292 3293 status_t 3294 BMessage::ReplaceData(const char* name, type_code type, const void* data, 3295 ssize_t numBytes) 3296 { 3297 return ReplaceData(name, type, 0, data, numBytes); 3298 } 3299 3300 3301 bool 3302 BMessage::HasFlat(const char* name, const BFlattenable* object) const 3303 { 3304 return HasFlat(name, 0, object); 3305 } 3306 3307 3308 bool 3309 BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object) 3310 const 3311 { 3312 return HasData(name, object->TypeCode(), index); 3313 } 3314 3315 3316 const char* 3317 BMessage::GetString(const char* name, const char* defaultValue) const 3318 { 3319 return GetString(name, 0, defaultValue); 3320 } 3321 3322 3323 const char* 3324 BMessage::GetString(const char* name, int32 index, 3325 const char* defaultValue) const 3326 { 3327 const char* value; 3328 if (FindString(name, index, &value) == B_OK) 3329 return value; 3330 3331 return defaultValue; 3332 } 3333 3334 3335 status_t 3336 BMessage::SetString(const char* name, const BString& value) 3337 { 3338 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1, 3339 false); 3340 } 3341 3342 3343 status_t 3344 BMessage::SetString(const char* name, const char* value) 3345 { 3346 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false); 3347 } 3348 3349 3350 status_t 3351 BMessage::SetData(const char* name, type_code type, const void* data, 3352 ssize_t numBytes, bool fixedSize, int count) 3353 { 3354 if (numBytes <= 0 || data == NULL) 3355 return B_BAD_VALUE; 3356 3357 if (ReplaceData(name, type, data, numBytes) == B_OK) 3358 return B_OK; 3359 3360 return AddData(name, type, data, numBytes, fixedSize, count); 3361 } 3362