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