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 #ifdef 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 >= 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 return result; 1955 target = info.team; 1956 } 1957 1958 void *address = NULL; 1959 area_id transfered = _kern_transfer_area(header->message_area, 1960 &address, B_ANY_ADDRESS, target); 1961 if (transfered < B_OK) { 1962 delete_area(header->message_area); 1963 free(header); 1964 return transfered; 1965 } 1966 1967 header->message_area = transfered; 1968 #endif 1969 } else { 1970 size = _NativeFlattenedSize(); 1971 buffer = (char *)malloc(size); 1972 if (buffer == NULL) 1973 return B_NO_MEMORY; 1974 1975 result = _NativeFlatten(buffer, size); 1976 if (result < B_OK) { 1977 free(buffer); 1978 return result; 1979 } 1980 1981 header = (message_header *)buffer; 1982 } 1983 1984 if (!replyTo.IsValid()) { 1985 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 1986 fHeader->reply_port, fHeader->reply_target); 1987 1988 if (!replyTo.IsValid()) 1989 replyTo = be_app_messenger; 1990 } 1991 1992 BMessenger::Private replyToPrivate(replyTo); 1993 1994 if (replyRequired) { 1995 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 1996 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 1997 } 1998 1999 header->target = token; 2000 header->reply_team = replyToPrivate.Team(); 2001 header->reply_port = replyToPrivate.Port(); 2002 header->reply_target = replyToPrivate.Token(); 2003 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2004 2005 if (direct == NULL) { 2006 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2007 "message: '%c%c%c%c'", portOwner, port, token, 2008 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2009 2010 do { 2011 result = write_port_etc(port, kPortMessageCode, (void *)buffer, size, 2012 B_RELATIVE_TIMEOUT, timeout); 2013 } while (result == B_INTERRUPTED); 2014 } 2015 2016 if (result == B_OK && IsSourceWaiting()) { 2017 // the forwarded message will handle the reply - we must not do 2018 // this anymore 2019 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2020 } 2021 2022 // we need to do this last because it is possible our 2023 // message might be destroyed after it's enqueued in the 2024 // target looper. Thus we don't want to do any ops that depend on 2025 // members of this after the enqueue. 2026 if (direct != NULL) { 2027 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2028 "message: '%c%c%c%c'", port, token, 2029 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2030 2031 // this is a local message transmission 2032 direct->AddMessage(copy); 2033 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2034 // there is currently no message waiting, and we need to wakeup the looper 2035 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2036 } 2037 direct->Release(); 2038 } 2039 2040 free(buffer); 2041 return result; 2042 } 2043 2044 2045 /*! 2046 Sends a message and waits synchronously for a reply. 2047 */ 2048 status_t 2049 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2050 BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2051 { 2052 if (IsSourceWaiting()) { 2053 // we can't forward this message synchronously when it's already 2054 // waiting for a reply 2055 return B_ERROR; 2056 } 2057 2058 DEBUG_FUNCTION_ENTER; 2059 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2060 port_id replyPort = B_BAD_PORT_ID; 2061 status_t result = B_OK; 2062 2063 if (cachedReplyPort < B_OK) { 2064 // All the cached reply ports are in use; create a new one 2065 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2066 if (replyPort < B_OK) 2067 return replyPort; 2068 } else { 2069 assert(cachedReplyPort < sNumReplyPorts); 2070 replyPort = sReplyPorts[cachedReplyPort]; 2071 } 2072 2073 team_id team = B_BAD_TEAM_ID; 2074 if (be_app != NULL) 2075 team = be_app->Team(); 2076 else { 2077 port_info portInfo; 2078 result = get_port_info(replyPort, &portInfo); 2079 if (result < B_OK) 2080 goto error; 2081 2082 team = portInfo.team; 2083 } 2084 2085 result = set_port_owner(replyPort, portOwner); 2086 if (result < B_OK) 2087 goto error; 2088 2089 // tests if the queue of the reply port is really empty 2090 #if 0 2091 port_info portInfo; 2092 if (get_port_info(replyPort, &portInfo) == B_OK 2093 && portInfo.queue_count > 0) { 2094 debugger("reply port not empty!"); 2095 printf(" reply port not empty! %ld message(s) in queue\n", 2096 portInfo.queue_count); 2097 2098 // fetch and print the messages 2099 for (int32 i = 0; i < portInfo.queue_count; i++) { 2100 char buffer[1024]; 2101 int32 code; 2102 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2103 if (size < 0) { 2104 printf("failed to read message from reply port\n"); 2105 continue; 2106 } 2107 if (size >= (ssize_t)sizeof(buffer)) { 2108 printf("message from reply port too big\n"); 2109 continue; 2110 } 2111 2112 BMemoryIO stream(buffer, size); 2113 BMessage reply; 2114 if (reply.Unflatten(&stream) != B_OK) { 2115 printf("failed to unflatten message from reply port\n"); 2116 continue; 2117 } 2118 2119 printf("message %ld from reply port:\n", i); 2120 reply.PrintToStream(); 2121 } 2122 } 2123 #endif 2124 2125 { 2126 BMessenger replyTarget; 2127 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2128 B_PREFERRED_TOKEN); 2129 // TODO: replying could also use a BDirectMessageTarget like mechanism for local targets 2130 result = _SendMessage(port, -1, token, sendTimeout, true, 2131 replyTarget); 2132 } 2133 2134 if (result < B_OK) 2135 goto error; 2136 2137 int32 code; 2138 result = handle_reply(replyPort, &code, replyTimeout, reply); 2139 if (result < B_OK && cachedReplyPort >= 0) { 2140 delete_port(replyPort); 2141 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2142 } 2143 2144 error: 2145 if (cachedReplyPort >= 0) { 2146 // Reclaim ownership of cached port 2147 set_port_owner(replyPort, team); 2148 // Flag as available 2149 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2150 return result; 2151 } 2152 2153 delete_port(replyPort); 2154 return result; 2155 } 2156 2157 2158 status_t 2159 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, 2160 int32 token, bigtime_t timeout) 2161 { 2162 DEBUG_FUNCTION_ENTER2; 2163 if (!data) 2164 return B_BAD_VALUE; 2165 2166 uint32 magic = *(uint32 *)data; 2167 2168 if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2169 message_header *header = (message_header *)data; 2170 header->target = token; 2171 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2172 } else if (magic == MESSAGE_FORMAT_R5) { 2173 uint8 *header = (uint8 *)data; 2174 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2175 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2176 + sizeof(uint8) /* flags */; 2177 *(int32 *)header = token; 2178 } else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) { 2179 KMessage::Header *header = (KMessage::Header *)data; 2180 header->targetToken = token; 2181 } else { 2182 return B_NOT_A_MESSAGE; 2183 } 2184 2185 // send the message 2186 status_t result; 2187 2188 do { 2189 result = write_port_etc(port, kPortMessageCode, data, size, 2190 B_RELATIVE_TIMEOUT, timeout); 2191 } while (result == B_INTERRUPTED); 2192 2193 return result; 2194 } 2195 2196 2197 void BMessage::_ReservedMessage1(void) {}; 2198 void BMessage::_ReservedMessage2(void) {}; 2199 void BMessage::_ReservedMessage3(void) {}; 2200 2201 2202 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2203 2204 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2205 status_t \ 2206 BMessage::Add##typeName(const char *name, type val) \ 2207 { \ 2208 return AddData(name, typeCode, &val, sizeof(type), true); \ 2209 } \ 2210 \ 2211 status_t \ 2212 BMessage::Find##typeName(const char *name, type *p) const \ 2213 { \ 2214 void *ptr = NULL; \ 2215 ssize_t bytes = 0; \ 2216 status_t error = B_OK; \ 2217 \ 2218 *p = type(); \ 2219 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 2220 \ 2221 if (error == B_OK) \ 2222 memcpy(p, ptr, sizeof(type)); \ 2223 \ 2224 return error; \ 2225 } \ 2226 \ 2227 status_t \ 2228 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 2229 { \ 2230 void *ptr = NULL; \ 2231 ssize_t bytes = 0; \ 2232 status_t error = B_OK; \ 2233 \ 2234 *p = type(); \ 2235 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 2236 \ 2237 if (error == B_OK) \ 2238 memcpy(p, ptr, sizeof(type)); \ 2239 \ 2240 return error; \ 2241 } \ 2242 \ 2243 status_t \ 2244 BMessage::Replace##typeName(const char *name, type val) \ 2245 { \ 2246 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \ 2247 } \ 2248 \ 2249 status_t \ 2250 BMessage::Replace##typeName(const char *name, int32 index, type val) \ 2251 { \ 2252 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \ 2253 } \ 2254 \ 2255 bool \ 2256 BMessage::Has##typeName(const char *name, int32 index) const \ 2257 { \ 2258 return HasData(name, typeCode, index); \ 2259 } 2260 2261 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2262 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2263 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2264 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2265 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2266 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2267 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2268 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2269 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2270 2271 #undef DEFINE_FUNCTIONS 2272 2273 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2274 bool \ 2275 BMessage::Has##typeName(const char *name, int32 index) const \ 2276 { \ 2277 return HasData(name, typeCode, index); \ 2278 } 2279 2280 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2281 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2282 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2283 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2284 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2285 2286 #undef DEFINE_HAS_FUNCTION 2287 2288 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2289 type \ 2290 BMessage::Find##typeName(const char *name, int32 index) const \ 2291 { \ 2292 type val = initialize; \ 2293 Find##typeName(name, index, &val); \ 2294 return val; \ 2295 } 2296 2297 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2298 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2299 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 2300 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2301 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2302 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2303 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2304 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2305 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2306 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2307 2308 #undef DEFINE_LAZY_FIND_FUNCTION 2309 2310 status_t 2311 BMessage::AddString(const char *name, const char *string) 2312 { 2313 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false); 2314 } 2315 2316 2317 status_t 2318 BMessage::AddString(const char *name, const BString &string) 2319 { 2320 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false); 2321 } 2322 2323 2324 status_t 2325 BMessage::AddPointer(const char *name, const void *pointer) 2326 { 2327 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2328 } 2329 2330 2331 status_t 2332 BMessage::AddMessenger(const char *name, BMessenger messenger) 2333 { 2334 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2335 } 2336 2337 2338 status_t 2339 BMessage::AddRef(const char *name, const entry_ref *ref) 2340 { 2341 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2342 char buffer[size]; 2343 2344 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2345 2346 if (error >= B_OK) 2347 error = AddData(name, B_REF_TYPE, buffer, size, false); 2348 2349 return error; 2350 } 2351 2352 2353 status_t 2354 BMessage::AddMessage(const char *name, const BMessage *message) 2355 { 2356 /* ToDo: This and the following functions waste time by allocating and 2357 copying an extra buffer. Functions can be added that return a direct 2358 pointer into the message. */ 2359 2360 char stackBuffer[16384]; 2361 ssize_t size = message->FlattenedSize(); 2362 2363 bool freeBuffer = false; 2364 char* buffer; 2365 if (size > (ssize_t)sizeof(stackBuffer)) { 2366 freeBuffer = true; 2367 buffer = static_cast<char*>(malloc(size)); 2368 if (buffer == NULL) 2369 return B_NO_MEMORY; 2370 } else { 2371 buffer = stackBuffer; 2372 } 2373 2374 status_t error = message->Flatten(buffer, size); 2375 2376 if (error >= B_OK) 2377 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2378 2379 if (freeBuffer) 2380 free(buffer); 2381 2382 return error; 2383 } 2384 2385 2386 status_t 2387 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 2388 { 2389 ssize_t size = object->FlattenedSize(); 2390 char buffer[size]; 2391 2392 status_t error = object->Flatten(buffer, size); 2393 2394 if (error >= B_OK) 2395 error = AddData(name, object->TypeCode(), &buffer, size, false); 2396 2397 return error; 2398 } 2399 2400 2401 status_t 2402 BMessage::FindString(const char *name, const char **string) const 2403 { 2404 return FindString(name, 0, string); 2405 } 2406 2407 2408 status_t 2409 BMessage::FindString(const char *name, int32 index, const char **string) const 2410 { 2411 ssize_t bytes; 2412 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 2413 } 2414 2415 2416 status_t 2417 BMessage::FindString(const char *name, BString *string) const 2418 { 2419 return FindString(name, 0, string); 2420 } 2421 2422 2423 status_t 2424 BMessage::FindString(const char *name, int32 index, BString *string) const 2425 { 2426 const char *cstr; 2427 status_t error = FindString(name, index, &cstr); 2428 if (error < B_OK) 2429 return error; 2430 2431 *string = cstr; 2432 return B_OK; 2433 } 2434 2435 2436 status_t 2437 BMessage::FindPointer(const char *name, void **pointer) const 2438 { 2439 return FindPointer(name, 0, pointer); 2440 } 2441 2442 2443 status_t 2444 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 2445 { 2446 void **data = NULL; 2447 ssize_t size = 0; 2448 status_t error = FindData(name, B_POINTER_TYPE, index, 2449 (const void **)&data, &size); 2450 2451 if (error == B_OK) 2452 *pointer = *data; 2453 else 2454 *pointer = NULL; 2455 2456 return error; 2457 } 2458 2459 2460 status_t 2461 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 2462 { 2463 return FindMessenger(name, 0, messenger); 2464 } 2465 2466 2467 status_t 2468 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 2469 const 2470 { 2471 void *data = NULL; 2472 ssize_t size = 0; 2473 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2474 (const void **)&data, &size); 2475 2476 if (error == B_OK) 2477 memcpy(messenger, data, sizeof(BMessenger)); 2478 else 2479 *messenger = BMessenger(); 2480 2481 return error; 2482 } 2483 2484 2485 status_t 2486 BMessage::FindRef(const char *name, entry_ref *ref) const 2487 { 2488 return FindRef(name, 0, ref); 2489 } 2490 2491 2492 status_t 2493 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 2494 { 2495 void *data = NULL; 2496 ssize_t size = 0; 2497 status_t error = FindData(name, B_REF_TYPE, index, 2498 (const void **)&data, &size); 2499 2500 if (error == B_OK) 2501 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 2502 else 2503 *ref = entry_ref(); 2504 2505 return error; 2506 } 2507 2508 2509 status_t 2510 BMessage::FindMessage(const char *name, BMessage *message) const 2511 { 2512 return FindMessage(name, 0, message); 2513 } 2514 2515 2516 status_t 2517 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 2518 { 2519 void *data = NULL; 2520 ssize_t size = 0; 2521 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2522 (const void **)&data, &size); 2523 2524 if (error == B_OK) 2525 error = message->Unflatten((const char *)data); 2526 else 2527 *message = BMessage(); 2528 2529 return error; 2530 } 2531 2532 2533 status_t 2534 BMessage::FindFlat(const char *name, BFlattenable *object) const 2535 { 2536 return FindFlat(name, 0, object); 2537 } 2538 2539 2540 status_t 2541 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 2542 { 2543 void *data = NULL; 2544 ssize_t numBytes = 0; 2545 status_t error = FindData(name, object->TypeCode(), index, 2546 (const void **)&data, &numBytes); 2547 2548 if (error == B_OK) 2549 error = object->Unflatten(object->TypeCode(), data, numBytes); 2550 2551 return error; 2552 } 2553 2554 2555 status_t 2556 BMessage::FindData(const char *name, type_code type, const void **data, 2557 ssize_t *numBytes) const 2558 { 2559 return FindData(name, type, 0, data, numBytes); 2560 } 2561 2562 2563 status_t 2564 BMessage::ReplaceString(const char *name, const char *string) 2565 { 2566 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 2567 } 2568 2569 2570 status_t 2571 BMessage::ReplaceString(const char *name, int32 index, const char *string) 2572 { 2573 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 2574 } 2575 2576 2577 status_t 2578 BMessage::ReplaceString(const char *name, const BString &string) 2579 { 2580 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 2581 string.Length() + 1); 2582 } 2583 2584 2585 status_t 2586 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 2587 { 2588 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 2589 string.Length() + 1); 2590 } 2591 2592 2593 status_t 2594 BMessage::ReplacePointer(const char *name, const void *pointer) 2595 { 2596 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 2597 } 2598 2599 2600 status_t 2601 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 2602 { 2603 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 2604 } 2605 2606 2607 status_t 2608 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 2609 { 2610 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 2611 sizeof(BMessenger)); 2612 } 2613 2614 2615 status_t 2616 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 2617 { 2618 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 2619 sizeof(BMessenger)); 2620 } 2621 2622 2623 status_t 2624 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 2625 { 2626 return ReplaceRef(name, 0, ref); 2627 } 2628 2629 2630 status_t 2631 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 2632 { 2633 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2634 char buffer[size]; 2635 2636 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2637 2638 if (error >= B_OK) 2639 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 2640 2641 return error; 2642 } 2643 2644 2645 status_t 2646 BMessage::ReplaceMessage(const char *name, const BMessage *message) 2647 { 2648 return ReplaceMessage(name, 0, message); 2649 } 2650 2651 2652 status_t 2653 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 2654 { 2655 ssize_t size = message->FlattenedSize(); 2656 char buffer[size]; 2657 2658 status_t error = message->Flatten(buffer, size); 2659 2660 if (error >= B_OK) 2661 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 2662 2663 return error; 2664 } 2665 2666 2667 status_t 2668 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 2669 { 2670 return ReplaceFlat(name, 0, object); 2671 } 2672 2673 2674 status_t 2675 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 2676 { 2677 ssize_t size = object->FlattenedSize(); 2678 char buffer[size]; 2679 2680 status_t error = object->Flatten(buffer, size); 2681 2682 if (error >= B_OK) 2683 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 2684 2685 return error; 2686 } 2687 2688 2689 status_t 2690 BMessage::ReplaceData(const char *name, type_code type, const void *data, 2691 ssize_t numBytes) 2692 { 2693 return ReplaceData(name, type, 0, data, numBytes); 2694 } 2695 2696 2697 bool 2698 BMessage::HasFlat(const char *name, const BFlattenable *object) const 2699 { 2700 return HasFlat(name, 0, object); 2701 } 2702 2703 2704 bool 2705 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 2706 const 2707 { 2708 return HasData(name, object->TypeCode(), index); 2709 } 2710