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