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